diff --git a/README.md b/README.md index 70358eb..be77ae4 100644 Binary files a/README.md and b/README.md differ diff --git a/src/assets/images/화면구성도_다이어그램.png b/src/assets/images/화면구성도_다이어그램.png deleted file mode 100644 index 9783ca0..0000000 Binary files a/src/assets/images/화면구성도_다이어그램.png and /dev/null differ diff --git a/src/assets/images/화면구성도다이어그램.png b/src/assets/images/화면구성도다이어그램.png new file mode 100644 index 0000000..45db312 Binary files /dev/null and b/src/assets/images/화면구성도다이어그램.png differ diff --git a/src/components/analysis/simulation/AnalysisSimuationInfo.js b/src/components/analysis/simulation/AnalysisSimuationInfo.js index f7a3d72..9d73cf3 100644 --- a/src/components/analysis/simulation/AnalysisSimuationInfo.js +++ b/src/components/analysis/simulation/AnalysisSimuationInfo.js @@ -6,8 +6,10 @@ import { Spinner } from 'reactstrap'; export const AnalysisSimulationInfo = props => { const [target, setTarget] = useState(null); + // 로딩 상태 const { loading } = useSelector(state => state.loadingReducer); + // 스크롤 끝 감지 데이터 추가 const onIntersect = useCallback( ([entry], observer) => { if (entry.isIntersecting) { @@ -19,6 +21,7 @@ export const AnalysisSimulationInfo = props => { [props.handlerPageList] ); + // 무한 스크롤 useEffect(() => { let observer; if (target) { diff --git a/src/components/analysis/simulation/AnalysisSimulationDetail.js b/src/components/analysis/simulation/AnalysisSimulationDetail.js index 35aa6e8..97f46a3 100644 --- a/src/components/analysis/simulation/AnalysisSimulationDetail.js +++ b/src/components/analysis/simulation/AnalysisSimulationDetail.js @@ -11,6 +11,7 @@ import { ReactComponent as Simulation_icon } from '../../../assets/images/simula import { IMG_PATH } from '../../../configs/constants'; import AnalysisSimulatorSlider from './AnalysisSimulatorSlider'; export const AnalysisSimulationDetail = props => { + // 슬라이드 진행 방향 const [isRtl, setIsRtl] = useRTL(); return ( diff --git a/src/components/analysis/simulation/AnalysisSimulationMap.js b/src/components/analysis/simulation/AnalysisSimulationMap.js index c3db44f..d6fbd52 100644 --- a/src/components/analysis/simulation/AnalysisSimulationMap.js +++ b/src/components/analysis/simulation/AnalysisSimulationMap.js @@ -9,12 +9,15 @@ import { Threebox } from 'threebox-plugin'; import gimPo from '../../map/geojson/gimpoAirportAirArea.json'; export const AnalysisSimulationMap = props => { + // 지도 const mapContainer = useRef(null); + // mabboxgl 지도 초기화 useEffect(() => { mapBoxMapInit(); }, []); + // mabboxgl 지도 초기화 함수 const mapBoxMapInit = () => { mapboxgl.accessToken = MAPBOX_TOKEN; diff --git a/src/components/analysis/simulation/AnalysisSimulationMarker.js b/src/components/analysis/simulation/AnalysisSimulationMarker.js index 0a0e201..715e7ab 100644 --- a/src/components/analysis/simulation/AnalysisSimulationMarker.js +++ b/src/components/analysis/simulation/AnalysisSimulationMarker.js @@ -3,6 +3,7 @@ import DronIcon from '../../../assets/images/drone-marker-icon.png'; import mapboxgl from 'mapbox-gl'; export const AnalysisSimulationMarker = props => { + // 마커 css const el = document.createElement('div'); el.className = 'marker'; el.style.width = '30px'; @@ -10,6 +11,7 @@ export const AnalysisSimulationMarker = props => { el.style.textAlign = 'center'; el.style.backgroundImage = `url(${DronIcon})`; + // 마커 경로 담기 useEffect(() => { if (props.selMarker && props.selMarker.setMap) { props.selMarker.setMap(null); @@ -30,6 +32,7 @@ export const AnalysisSimulationMarker = props => { } }, [props.data]); + // 매 초마다 경로 이동 useEffect(() => { if (props.isPlay) { if (props.marker) { @@ -47,6 +50,7 @@ export const AnalysisSimulationMarker = props => { } }, [props.info]); + // 지도 드론 표출 const addMarkers = (position, id) => { // 이미 지정된 마커 제거 if (props.marker) { diff --git a/src/components/analysis/simulation/AnalysisSimulationPolyline.js b/src/components/analysis/simulation/AnalysisSimulationPolyline.js index 305b4c1..7030c74 100644 --- a/src/components/analysis/simulation/AnalysisSimulationPolyline.js +++ b/src/components/analysis/simulation/AnalysisSimulationPolyline.js @@ -1,8 +1,10 @@ import { useEffect } from 'react'; export const AnalysisSimulationPolyline = props => { + // 폴리라인 경로 담는 변수 const polylinePath = []; + // 기존 저장된 경로 삭제 useEffect(() => { // 기존 폴리라인 삭제 처리 if (props.selPolyline && props.selPolyline.setMap) { @@ -19,6 +21,7 @@ export const AnalysisSimulationPolyline = props => { } }, [props.data]); + // 경로 그리기 const addPolyline = () => { if (props.data && props.map) { props.data.forEach(item => { diff --git a/src/components/analysis/simulation/AnalysisSimulationReport.js b/src/components/analysis/simulation/AnalysisSimulationReport.js index 4be4be6..6d118eb 100644 --- a/src/components/analysis/simulation/AnalysisSimulationReport.js +++ b/src/components/analysis/simulation/AnalysisSimulationReport.js @@ -5,6 +5,7 @@ import Flatpickr from 'react-flatpickr'; import { Button, Input, InputGroup } from 'reactstrap'; export const AnalysisSimulationReport = props => { + // 식별번호 const [filterId, setFilterId] = useState(''); return ( diff --git a/src/components/analysis/simulation/AnalysisSimulatorSlider.js b/src/components/analysis/simulation/AnalysisSimulatorSlider.js index 87b643a..b26f796 100644 --- a/src/components/analysis/simulation/AnalysisSimulatorSlider.js +++ b/src/components/analysis/simulation/AnalysisSimulatorSlider.js @@ -24,6 +24,7 @@ const AnalysisSimulatorSlider = ({ return timeString; } + // 슬라이더 값이 바뀔 때마다 실행되는 함수 const colorOptions = { start: [playCount ? playCount : 0], // connect: true, @@ -64,7 +65,6 @@ const AnalysisSimulatorSlider = ({ direction }; - useEffect(() => {}, [playCount]); return (
{/*
Default / Primary Color Slider
*/} diff --git a/src/components/laanc/list/LaancDetail.js b/src/components/laanc/list/LaancDetail.js index 904de47..3837a1f 100644 --- a/src/components/laanc/list/LaancDetail.js +++ b/src/components/laanc/list/LaancDetail.js @@ -30,7 +30,9 @@ export default function LaancDetail({ data, handlerLaancClose }) { 11: '25kg초과' } }; + // 로그인 정보 const { user } = useSelector(state => state.authState); + // 약관 정보 const { termsList } = useSelector(state => state.accountState); // Laanc 약관 동의 diff --git a/src/components/laanc/list/LaancGrid.js b/src/components/laanc/list/LaancGrid.js index 65f4698..ca3b796 100644 --- a/src/components/laanc/list/LaancGrid.js +++ b/src/components/laanc/list/LaancGrid.js @@ -18,11 +18,13 @@ pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/$ export default function LaancGrid() { const dispatch = useDispatch(); + // 상세보기 모달 const [isAnimation, setIsAnimation] = useState(false); - + // Laanc 승인 신청 목록 const { laancSearchData, laancDetail } = useSelector( state => state.laancState ); + // 로딩 상태 const { loading } = useSelector(state => state.loadingReducer); // Laanc 승인 신청 목록 조회 @@ -169,6 +171,7 @@ export default function LaancGrid() { } ]; + // PDF 다운로드 const handlerPdfDownload = pdf => { if (pdf) { let alink = document.createElement('a'); diff --git a/src/components/laanc/list/LaancSearch.js b/src/components/laanc/list/LaancSearch.js index 649281e..2e93a14 100644 --- a/src/components/laanc/list/LaancSearch.js +++ b/src/components/laanc/list/LaancSearch.js @@ -8,7 +8,7 @@ import * as LaancAction from '../../../modules/laanc/actions/laancActions'; function LaancSearch({ isSearch }) { const dispatch = useDispatch(); - + // 날짜 데이터 const [date, setDate] = useState({ createStDate: moment().subtract(0, 'day').format('YYYY-MM-DD'), createEndDate: moment().subtract(-7, 'day').format('YYYY-MM-DD') diff --git a/src/components/laanc/map/FlightArea.js b/src/components/laanc/map/FlightArea.js index 401dde8..c7bdfbf 100644 --- a/src/components/laanc/map/FlightArea.js +++ b/src/components/laanc/map/FlightArea.js @@ -1,6 +1,9 @@ +import { useEffect, useRef, useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'; +// mapbox import 'mapbox-gl/dist/mapbox-gl.css'; import mapboxgl from 'mapbox-gl'; -import threebox from 'threebox-plugin'; import MapboxLanguage from '@mapbox/mapbox-gl-language'; import MapboxDraw from '@mapbox/mapbox-gl-draw'; import { @@ -10,18 +13,6 @@ import { SimpleSelectMode } from 'mapbox-gl-draw-circle'; import { MAPBOX_TOKEN } from '../../../configs/constants'; -import { useEffect, useRef, useState } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; -import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'; -import { - AREA_COORDINATE_LIST_SAVE, - AREA_DETAIL_LIST_SAVE -} from '../../../modules/basis/flight/actions/basisFlightAction'; -import { - drawTypeChangeAction, - mapInitAction -} from '../../../modules/control/map/actions/controlMapActions'; -import LaancAreaMap from './LaancAreaMap'; import { InitFeature, handlerCreatePoint, @@ -32,20 +23,26 @@ import { layerPolyline, layerWayPoint } from '../../../utility/DrawUtil'; -import flatGimpo from '../../map/geojson/flatGimpoAirportAirArea.json'; +// actions +import { + AREA_COORDINATE_LIST_SAVE, + AREA_DETAIL_LIST_SAVE +} from '../../../modules/basis/flight/actions/basisFlightAction'; +import { + drawTypeChangeAction, + mapInitAction +} from '../../../modules/control/map/actions/controlMapActions'; +import * as LaancAction from '../../../modules/laanc/actions/laancActions'; +// geojson import gimpo from '../../map/geojson/gimpoAirportAirArea.json'; -import geoJson from '../../map/geojson/airArea.json'; + +import threebox from 'threebox-plugin'; import { FeatureAirZone } from '../../map/mapbox/feature/FeatureAirZone'; import { WeatherContainer } from '../../../containers/basis/flight/plan/WeatherContainer'; import { initFlightBas } from '../../../modules/laanc/models/laancModels'; -import * as LaancAction from '../../../modules/laanc/actions/laancActions'; +import LaancAreaMap from './LaancAreaMap'; import LaancDrawModal from './LaancDrawModal'; - -const initialAddData = { - isAddable: false, - isViewAdd: false, - overAdd: false -}; +import { handlerCreateAirSpace } from './LaancComn'; export default function FlightArea({ centeredModal, @@ -61,40 +58,65 @@ export default function FlightArea({ >; const dispatch = useDispatch(); - const { areaCoordList } = useSelector(state => state.flightState); + // 비행구역 타입 및 공역 타입 const mapControl = useSelector(state => state.controlMapReducer); - const mapContainer = useRef(null); + // 비행구역 정보 저장 + const { areaCoordList } = useSelector(state => state.flightState); + + // 지도 const [mapObject, setMapObject] = useState(); - const [drawObj, setDrawObj] = useState(); + const mapContainer = useRef(null); + // 지도 로드 여부 const [isMapLoad, setIsMapLoad] = useState(false); + + // 비행구역 그리기 + const [drawObj, setDrawObj] = useState(); + + // 미니맵 레이어 const [previewLayer, setPreviewLayer] = useState(); + + // 날씨 모달 const [formModal, setFormModal] = useState(false); + // 비행구역 설정 관련 모달 const [modal, setModal] = useState({ title: '', desc: '', isOpen: false }); + // 비행구역 저장 가능 여부 const [isSaveable, setIsSaveable] = useState(false); - const [addData, setAddData] = useState(initialAddData); + // 비행구역 추가 가능 여부 판단 + const [addData, setAddData] = useState({ + isAddable: false, + isViewAdd: false, + overAdd: false + }); + + // 저장된 비행구역 데이터 const [saveData, setSaveData] = useState(); + + // 비행구역 고도 const [saveElev, setSaveElev] = useState(); - //날씨 임시 데이터 + //날씨 위치 데이터 const [wheather, setWheather] = useState([]); + // 미니맵에 표출되는 비행구역 정보 const previewGeo = { type: 'FeatureCollection', features: [] }; + // 지도 초기 셋팅 useEffect(() => { handlerMapInit(); }, []); + // 미니맵에 비행구역 표출 및 날씨 정보 저장 useEffect(() => { if (areaCoordList) { const area = areaCoordList[0]; @@ -105,78 +127,12 @@ export default function FlightArea({ } }, [areaCoordList, centeredModal, previewLayer]); - const handlerCreateAirSpace = ( - map, - useGeoJson = { - ...geoJson, - ...flatGimpo, - features: [...geoJson.features, ...flatGimpo.features] - } - ) => { - if (map.getLayer('maine')) { - map.removeLayer('maine'); - map.removeSource('maine'); - } - let arrGeoJson = []; - useGeoJson.features.map(item => { - if (item.properties.type === '0001' && mapControl.area0001) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#FF3648' } - }); - } else if (item.properties.type === '0002' && mapControl.area0002) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#FFA1AA' } - }); - } else if (item.properties.type === '0003' && mapControl.area0003) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#FFA800' } - }); - } else if (item.properties.type === '0004' && mapControl.area0004) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#A16B00' } - }); - } else if (item.properties.type === '0005' && mapControl.area0005) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#AB40FF' } - }); - } else if (item.properties.type === '0006' && mapControl.area0006) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#009cad' } - }); - } - }); - useGeoJson.features = arrGeoJson.filter(i => i.geometry.type === 'Polygon'); - - // 공역 생성 start - map.addSource('maine', { - type: 'geojson', - data: { - ...useGeoJson - } - }); - map.addLayer({ - id: 'maine', - type: 'fill', - source: 'maine', - layout: {}, - paint: { - 'fill-color': ['get', 'color'], - // 'fill-extrusion-height': 3000, - 'fill-opacity': 0.5 - } - }); - }; - + // 비행구역 설정 관련 모달 표출 const handlerModal = () => { setModal(!modal); }; + // 비행구역 타입 변경 시 그리기 모드 상태일 때 에러 표출 const handlerDrawType = val => { if (drawObj.getMode().includes('draw')) { setModal({ @@ -195,6 +151,7 @@ export default function FlightArea({ } }; + // laanc계획서 비행구역 저장버튼 클릭 시 비행구역 정보 저장 const handlerSave = async () => { if (areaCoordList) { console.log('save'); @@ -208,29 +165,28 @@ export default function FlightArea({ setCenteredModal(false); dispatch(AREA_DETAIL_LIST_SAVE(resultAreaDetail)); - } else { - alert('아무것도 작성 안함'); } }; - // 날씨 handler + // 날씨 모달 표출 const handlerWeather = () => { setFormModal(!formModal); }; + // 지도 초기 셋팅 const handlerMapInit = () => { mapboxgl.accessToken = MAPBOX_TOKEN; const map = new mapboxgl.Map({ - container: 'preview', // container ID - style: 'mapbox://styles/mapbox/streets-v12', // style URL - center: [126.612647, 37.519893], // starting position [lng, lat] - // zoom: !areaCoordList ? 14 : bufferZoom.bufferzoom, // starting zoom + container: 'preview', + style: 'mapbox://styles/mapbox/streets-v12', + center: [126.612647, 37.519893], zoom: 15, antialias: true, attributionControl: false }); + // 비행구역 상세맵 draw 정보 셋팅 const draw = new MapboxDraw({ displayControlsDefault: false, userProperties: true, @@ -243,16 +199,14 @@ export default function FlightArea({ simple_select: SimpleSelectMode }, styles: [ - // line stroke { + // polyline id: 'gl-draw-line', type: 'line', filter: [ 'all', ['==', '$type', 'LineString'], ['!=', 'mode', 'static'] - // ['==', 'meta', 'feature'], - // ['==', 'active', 'false'] ], layout: { 'line-cap': 'round', @@ -264,28 +218,8 @@ export default function FlightArea({ 'line-width': 2 } }, - // direct line stroke - // { - // id: 'gl-draw-line-active', - // type: 'line', - // filter: [ - // 'all', - // ['==', '$type', 'LineString'], - // ['==', 'meta', 'feature'], - // ['==', 'active', 'true'] - // ], - // layout: { - // 'line-cap': 'round', - // 'line-join': 'round' - // }, - // paint: { - // 'line-color': '#000000', - // 'line-dasharray': [0.2, 2], - // 'line-width': 2 - // } - // }, - // polygon fill { + // polygon fill id: 'gl-draw-polygon-fill', type: 'fill', filter: ['all', ['==', '$type', 'Polygon'], ['!=', 'mode', 'static']], @@ -295,18 +229,7 @@ export default function FlightArea({ 'fill-opacity': 0.1 } }, - // polygon mid points - { - id: 'gl-draw-polygon-midpoint', - type: 'circle', - filter: ['all', ['==', '$type', 'Point'], ['==', 'meta', 'midpoint']], - paint: { - 'circle-radius': 4, - 'circle-color': '#8a1c05' - } - }, - // polygon outline stroke - // This doesn't style the first edge of the polygon, which uses the line stroke styling instead + // polygon outline { id: 'gl-draw-polygon-stroke-active', type: 'line', @@ -321,8 +244,8 @@ export default function FlightArea({ 'line-width': 2 } }, - // vertex point halos { + // vertex point halos id: 'gl-draw-polygon-and-line-vertex-halo-active', type: 'circle', filter: [ @@ -333,11 +256,11 @@ export default function FlightArea({ ], paint: { 'circle-radius': 8, - 'circle-color': '#fff' + 'circle-color': '#ffffff' } }, - // vertex points { + // vertex points id: 'gl-draw-polygon-and-line-vertex-active', type: 'circle', filter: [ @@ -359,7 +282,6 @@ export default function FlightArea({ const language = new MapboxLanguage(); map.addControl(language); - // map.addControl(draw); const tb = (window.tb = new threebox.Threebox( map, @@ -396,7 +318,7 @@ export default function FlightArea({ } }); - handlerCreateAirSpace(map); + handlerCreateAirSpace(map, mapControl); // 미니맵 표출 map.addSource('preview', { @@ -417,6 +339,7 @@ export default function FlightArea({ dispatch(mapInitAction(map)); }; + // 저장된 비행구역 미니맵에 표출 const handlerPreviewDraw = () => { if (areaCoordList) { const areas = areaCoordList[0]; @@ -427,7 +350,6 @@ export default function FlightArea({ let fitZoomPaths = []; - // 기존 if (areas.areaType) { if (areas.areaType === 'CIRCLE') { const radius = areas.bufferZone; @@ -478,12 +400,8 @@ export default function FlightArea({ //지도 줌 좌표 설정 fitZoomPaths = paths.concat(); - - // 마커 삭제 - // const ele = document.getElementById('mapboxgl-popup'); - // const eleArr = Array.from(ele); - // eleArr?.forEach(marker => marker.remove()); } + handlerFitBounds(mapObject, fitZoomPaths, 50, areas.areaType); mapObject.setPaintProperty('waypoint', 'circle-radius', 10); @@ -491,12 +409,13 @@ export default function FlightArea({ } const coordValue = []; - const coord = paths?.map(coords => { + paths?.map(coords => { coordValue.push({ lat: coords[1], lon: coords[0] }); }); + if (page === 1) { naver.maps.Service.reverseGeocode( { @@ -527,7 +446,6 @@ export default function FlightArea({ name: 'latlon', value: coordValue }); - //스텝1에 반경도 글씨가 바뀌어야 함...!! handleChange({ type: 'area', name: 'bufferZone', @@ -537,38 +455,33 @@ export default function FlightArea({ } }; + // 비행구역 추가 버튼 클릭 시 const handlerAddClick = () => { if (!addData.isAddable || !addData.overAdd) { handlerAddChange('isAddable', true); - const obj = drawObj - .getAll() - .features.filter(obj => obj.properties.id !== 'BUFFER'); - // handlerDrawType(obj[0].properties.id); } }; + // 비행구역 추가 관련 상태 변경 const handlerAddChange = (key, val) => { - // const [addData, setAddData] = useState({ - // isAddalbe: false, - // isViewAdd: false, - // overAdd: false - // }) - setAddData(prev => ({ ...prev, [key]: val })); }; + // 비행구역 저장 가능 유무 체크 const handlerSaveCheck = save => { setIsSaveable(save); }; + // 비행구역 데이터 초기화 const handlerInitCoordinates = () => { const init = initFlightBas.initDetail.areaList.concat(); dispatch(AREA_COORDINATE_LIST_SAVE(init)); }; + // 비행구역 고도 저장 const handlerSaveElev = elev => { setSaveElev(elev); }; @@ -604,7 +517,6 @@ export default function FlightArea({ - {/* 닫기 */} 저장
diff --git a/src/components/laanc/map/LaancAreaMap.js b/src/components/laanc/map/LaancAreaMap.js index 039f91e..0901ba2 100644 --- a/src/components/laanc/map/LaancAreaMap.js +++ b/src/components/laanc/map/LaancAreaMap.js @@ -3,7 +3,7 @@ import mapboxgl from 'mapbox-gl'; import threebox from 'threebox-plugin'; import MapboxLanguage from '@mapbox/mapbox-gl-language'; import { MAPBOX_TOKEN } from '../../../configs/constants'; -import { useEffect, useMemo, useRef, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { Card, CardBody } from 'reactstrap'; import { initFlightBas } from '../../../modules/basis/flight/models/basisFlightModel'; @@ -16,22 +16,15 @@ import { mapInitAction } from '../../../modules/control/map/actions/controlMapAc import { FormattingCoord, handlerFitBounds, - handlerGetCircleCoord, - layerBuffer, - layerGuideLine, - layerPolygon, - layerPolyline, - layerWayPoint + handlerGetCircleCoord } from '../../../utility/DrawUtil'; -import flatGimpo from '../../map/geojson/flatGimpoAirportAirArea.json'; import gimpo from '../../map/geojson/gimpoAirportAirArea.json'; -import geoJson from '../../map/geojson/airArea.json'; import { FeatureAirZone } from '../../map/mapbox/feature/FeatureAirZone'; import LaancMapSearch from './LaancMapSearch'; import { LaancDrawControl } from './LaancDrawControl'; +import { handlerCreateAirSpace } from './LaancComn'; export default function LaancAreaMap({ - centeredModal, mapContainer, drawObj, handlerSaveCheck, @@ -43,42 +36,38 @@ export default function LaancAreaMap({ setModal }) { const dispatch = useDispatch(); + // 비행구역 타입 및 공역 타입 const mapControl = useSelector(state => state.controlMapReducer); - const { areaCoordList } = useSelector(state => state.flightState); - const [mapObject, setMapObject] = useState(); - const [isMapLoad, setIsMapLoad] = useState(false); - const [mode, setMode] = useState(); + // 비행구역 정보 저장 + const { areaCoordList } = useSelector(state => state.flightState); + // 비행구역 초기값 포함 정보 저장 const [mapAreaCoordList, setMapAreaCoordList] = useState( initFlightBas.initDetail.areaList ); - const [number, setNumber] = useState(0); + // 지도 + const [mapObject, setMapObject] = useState(); + // 지도 로드 여부 + const [isMapLoad, setIsMapLoad] = useState(false); - // const [detailLayer, setDetailLayer] = useState(); + // 지도 렌더 횟수 + const [number, setNumber] = useState(0); + // 비행구역 좌표 카드에 표출될 좌표 정보 const [viewCoordObj, setViewCoordObj] = useState([]); - const detailGeo = useMemo(() => { - return { - type: 'FeatureCollection', - features: [] - }; - }, []); - // 좌표 정보 마우스 드래그 const scrollRef = useRef(null); const [isDrag, setIsDrag] = useState(false); const [startX, setStartX] = useState(); + // 지도 초기 셋팅 useEffect(() => { handlerMapInit(); }, []); - useEffect(() => { - setMode(mapControl.drawType); - }, [mapControl.drawType]); - + // 첫 비행구역 생성 or 저장했던 비행구역 다시 열기 시 비행구역에 화면 맞추어서 zoom useEffect(() => { if (areaCoordList && mapObject) { if ( @@ -111,75 +100,7 @@ export default function LaancAreaMap({ } }, [areaCoordList, mapObject, number]); - // 공역 생성 - const handlerCreateAirSpace = ( - map, - useGeoJson = { - ...geoJson, - ...flatGimpo, - features: [...geoJson.features, ...flatGimpo.features] - } - ) => { - if (map.getLayer('maine')) { - map.removeLayer('maine'); - map.removeSource('maine'); - } - let arrGeoJson = []; - useGeoJson.features.map(item => { - if (item.properties.type === '0001' && mapControl.area0001) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#FF3648' } - }); - } else if (item.properties.type === '0002' && mapControl.area0002) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#FFA1AA' } - }); - } else if (item.properties.type === '0003' && mapControl.area0003) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#FFA800' } - }); - } else if (item.properties.type === '0004' && mapControl.area0004) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#A16B00' } - }); - } else if (item.properties.type === '0005' && mapControl.area0005) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#AB40FF' } - }); - } else if (item.properties.type === '0006' && mapControl.area0006) { - arrGeoJson.push({ - ...item, - properties: { ...item.properties, color: '#009cad' } - }); - } - }); - useGeoJson.features = arrGeoJson.filter(i => i.geometry.type === 'Polygon'); - - // 공역 생성 start - map.addSource('maine', { - type: 'geojson', - data: { - ...useGeoJson - } - }); - map.addLayer({ - id: 'maine', - type: 'fill', - source: 'maine', - layout: {}, - paint: { - 'fill-color': ['get', 'color'], - // 'fill-extrusion-height': 3000, - 'fill-opacity': 0.5 - } - }); - }; - + // 맵박스 지도 초기 셋팅 const handlerMapInit = () => { mapboxgl.accessToken = MAPBOX_TOKEN; @@ -187,7 +108,6 @@ export default function LaancAreaMap({ container: 'detail', // container ID style: 'mapbox://styles/mapbox/streets-v12', // style URL center: [126.612647, 37.519893], // starting position [lng, lat] - // zoom: !areaCoordList ? 14 : bufferZoom.bufferzoom, // starting zoom zoom: 15, antialias: true, attributionControl: false @@ -238,31 +158,15 @@ export default function LaancAreaMap({ } }); - map.addSource('detail', { - type: 'geojson', - data: detailGeo - }); - map.addLayer(layerWayPoint('detail')); - map.addLayer(layerGuideLine('detail')); - map.addLayer(layerPolyline('detail')); - map.addLayer(layerPolygon('detail')); - map.addLayer(layerBuffer('detail')); - - handlerCreateAirSpace(map); + handlerCreateAirSpace(map, mapControl); setIsMapLoad(true); - - // const detail = map.getSource('detail'); - // if (detail) setDetailLayer(detail); }); + setMapObject(map); dispatch(mapInitAction(map)); }; - // const handlerInitCoordinates = () => { - // const init = initFlightBas.initDetail.areaList.concat(); - // dispatch(AREA_COORDINATE_LIST_SAVE(init)); - // }; - + // areaInfo를 areaList 형식으로 반환 const handlerAreaInfoToAreaList = areaInfo => { const initAreaList = initFlightBas.initDetail.areaList.concat(); const coordList = []; @@ -287,10 +191,10 @@ export default function LaancAreaMap({ return areaList; }; + // 비행관제구역 체크 및 버퍼 생성 const handlerCoordinates = areaInfo => { const areaList = handlerAreaInfoToAreaList(areaInfo); - // dispatch(LaancAction.LAANC_ALTITUDE.request(areaList)); dispatch(LaancAction.LAANC_VALID_AREA.request(areaList)); if (areaInfo.areaType === 'LINE' || areaInfo.areaType === 'POLYGON') { dispatch(FLIGHT_PLAN_AREA_BUFFER_LIST.request(areaList)); @@ -299,6 +203,7 @@ export default function LaancAreaMap({ } }; + // 비행구역 설정 후 저장 const handlerConfirm = areaList => { if (areaList === undefined) { alert('영역을 설정해 주세요.'); @@ -308,17 +213,14 @@ export default function LaancAreaMap({ dispatch(AREA_COORDINATE_LIST_SAVE(areaList)); }; - // const handlerModal = () => { - // setModal(!modal); - // }; - - // 좌표 정보 마우스 드래그 + // [좌표 정보] 마우스 다운 시 스크롤 준비 const onMouseDown = e => { e.preventDefault(); setIsDrag(true); setStartX(e.pageX + scrollRef.current.scrollLeft); }; + // [좌표 정보] 마우스 드래그로 스크롤 이동 const onMouseMove = e => { if (isDrag) { const { scrollWidth, clientWidth, scrollLeft } = scrollRef.current; @@ -333,6 +235,7 @@ export default function LaancAreaMap({ } }; + // [좌표 정보] onMouseMove 이벤트 빈도 조절 const throttle = (func, ms) => { let throttled = false; return (...args) => { @@ -346,11 +249,13 @@ export default function LaancAreaMap({ }; }; + // [좌표 정보] 마우스 업 시 스크롤 멈춤 const onMouseUp = e => { e.preventDefault(); setIsDrag(false); }; + // [좌표 정보] 마우스 벗어날 시 스크롤 멈춤 const onMouseLeave = () => { setIsDrag(false); }; @@ -455,21 +360,20 @@ export default function LaancAreaMap({ {isMapLoad && mapObject ? ( <> diff --git a/src/components/laanc/map/LaancComn.js b/src/components/laanc/map/LaancComn.js new file mode 100644 index 0000000..d8e30a8 --- /dev/null +++ b/src/components/laanc/map/LaancComn.js @@ -0,0 +1,73 @@ +import { useSelector } from 'react-redux'; +import geoJson from '../../map/geojson/airArea.json'; +import flatGimpo from '../../map/geojson/flatGimpoAirportAirArea.json'; + +// 공역 생성 +export const handlerCreateAirSpace = ( + map, + mapControl, + useGeoJson = { + ...geoJson, + ...flatGimpo, + features: [...geoJson.features, ...flatGimpo.features] + } +) => { + if (map.getLayer('maine')) { + map.removeLayer('maine'); + map.removeSource('maine'); + } + let arrGeoJson = []; + useGeoJson.features.map(item => { + if (item.properties.type === '0001' && mapControl.area0001) { + arrGeoJson.push({ + ...item, + properties: { ...item.properties, color: '#FF3648' } + }); + } else if (item.properties.type === '0002' && mapControl.area0002) { + arrGeoJson.push({ + ...item, + properties: { ...item.properties, color: '#FFA1AA' } + }); + } else if (item.properties.type === '0003' && mapControl.area0003) { + arrGeoJson.push({ + ...item, + properties: { ...item.properties, color: '#FFA800' } + }); + } else if (item.properties.type === '0004' && mapControl.area0004) { + arrGeoJson.push({ + ...item, + properties: { ...item.properties, color: '#A16B00' } + }); + } else if (item.properties.type === '0005' && mapControl.area0005) { + arrGeoJson.push({ + ...item, + properties: { ...item.properties, color: '#AB40FF' } + }); + } else if (item.properties.type === '0006' && mapControl.area0006) { + arrGeoJson.push({ + ...item, + properties: { ...item.properties, color: '#009cad' } + }); + } + }); + useGeoJson.features = arrGeoJson.filter(i => i.geometry.type === 'Polygon'); + + // 공역 생성 start + map.addSource('maine', { + type: 'geojson', + data: { + ...useGeoJson + } + }); + map.addLayer({ + id: 'maine', + type: 'fill', + source: 'maine', + layout: {}, + paint: { + 'fill-color': ['get', 'color'], + // 'fill-extrusion-height': 3000, + 'fill-opacity': 0.5 + } + }); +}; diff --git a/src/components/laanc/map/LaancDrawControl.js b/src/components/laanc/map/LaancDrawControl.js index 0dd2ef9..58990f2 100644 --- a/src/components/laanc/map/LaancDrawControl.js +++ b/src/components/laanc/map/LaancDrawControl.js @@ -1,5 +1,4 @@ import { useEffect, useRef, useState } from 'react'; -import { InfoModal } from '../../modal/InfoModal'; import { ErrorModal } from '../../modal/ErrorModal'; import { useDispatch, useSelector } from 'react-redux'; import { @@ -25,36 +24,42 @@ import Constants from 'mapbox-gl-draw-circle/node_modules/@mapbox/mapbox-gl-draw export const LaancDrawControl = props => { const dispatch = useDispatch(); - - const mapControl = useSelector(state => state.controlMapReducer); - const drawObj = props.drawObj; + + // 지도 const mapObject = props.mapObject; + // 비행구역 타입 + const { drawType } = useSelector(state => state.controlMapReducer); + + // mapbox 기본 onClick 함수 저장 + const originClickRef = useRef(null); + + // 비행구역이 WayPoint일 때 bufferId const [bufferId, setBufferId] = useState(); + // 그리기모드 상태인지 유무 확인 const [isDrawDone, setIsDrawDone] = useState(false); - const [alertModal, setAlertModal] = useState({ - isOpen: false, - title: '', - desc: '' - }); + // 지도 렌더 횟수 + const [number, setNumber] = useState(0); + + // 에러 모달창 정보 const [isErrorModal, setIsErrorModal] = useState({ isOpen: false, title: '', desc: '' }); - const [number, setNumber] = useState(0); - + // 비행구역 타입 변경에 따른 그리기모드 셋팅 useEffect(() => { - if (mapControl.drawType === 'DONE') { - // 구역 생성 후 바로 directMode + if (drawType === 'DONE') { if (number !== 0) { const obj = drawObj .getAll() .features.filter(o => o.properties.id !== 'BUFFER'); + + // 구역 생성 후 바로 directMode if (obj.length > 0) { drawObj.changeMode('direct_select', { featureId: obj[obj.length - 1]?.id @@ -64,10 +69,9 @@ export const LaancDrawControl = props => { } else { drawInit(); } - }, [mapControl.drawType]); - - const originClickRef = useRef(null); + }, [drawType]); + // mapbox 기본 함수 오버라이드 및 함수 중복 등록 방지 useEffect(() => { if (mapObject) { const DrawLineStringMode = MapboxDraw.modes.draw_line_string; @@ -75,6 +79,7 @@ export const LaancDrawControl = props => { const DrawCircleMode = CircleMode; const modeArr = [DrawLineStringMode, DrawPolygonMode, DrawCircleMode]; + // 등록 함수 제거 const cleanUp = () => { modeArr.forEach(m => { m.onStop = null; @@ -154,6 +159,7 @@ export const LaancDrawControl = props => { setNumber(number + 1); } + // 컴포넌트 언마운트 시 return () => { dispatch(drawTypeChangeAction('DONE')); mapObject.off('draw.update', handlerUpdateSetting); @@ -162,10 +168,12 @@ export const LaancDrawControl = props => { } }, [mapObject]); + // 비행구역 데이터 지도에 다시 그려주기 useEffect(() => { handlerPastDraw(); }, [props.areaCoordList]); + // 비행구역 설정을 올바르게 마쳤을 때 좌표 저장 useEffect(() => { if (isDrawDone) { props.handlerConfirm(props.areaCoordList); @@ -173,7 +181,7 @@ export const LaancDrawControl = props => { } }, [isDrawDone]); - // 클릭할 때마다 마커 찍어줌 + // 클릭할 때마다 마커 표출 const handlerCustomOnClick = (state, e) => { const mode = handlerReturnMode(drawObj.getMode()); const obj = state[mode?.toLowerCase()]; @@ -181,7 +189,7 @@ export const LaancDrawControl = props => { if (mode && obj) { const feature = drawObj.get(obj.id); if (!feature) { - console.log('2222222222'); + // console.log('simple_select'); drawObj.changeMode('simple_select'); return; } @@ -220,7 +228,7 @@ export const LaancDrawControl = props => { } }; - // 도형 그리기 완료 시 + // 비행구역 그리기 완료 시 const handlerFinishDraw = state => { if (drawObj.getAll().features.length === 0) return; @@ -293,8 +301,7 @@ export const LaancDrawControl = props => { }); } } else { - console.log('333333333'); - // 좌표가 찍히기도 전에 틀만 생성된 도형들 삭제 + // console.log('좌표가 찍히기도 전에 틀만 생성된 도형들 삭제'); // if (mode === 'CIRCLE') { // const obj = state.polygon; // drawObj.delete(obj.id); @@ -307,7 +314,7 @@ export const LaancDrawControl = props => { // 모든 비정상상황 체크 const handlerAbnormalityCheck = async data => { - // radius도 있음 + // radius 존재함 const { coords, mode, id } = data; const areaInfo = handlerSettingAreaInfo(coords, mode); @@ -411,7 +418,7 @@ export const LaancDrawControl = props => { } }; - // 도형 수정 시 + // 비행구역 수정 시 const handlerUpdateSetting = e => { if (e.features[0]) { const { geometry, properties, id } = e.features[0]; @@ -482,7 +489,7 @@ export const LaancDrawControl = props => { ); props.setViewCoordObj(viewCoordObj); - // 계속 20개 미만이라 overAdd false처리(임시) + // 계속 20개 미만이라 overAdd false처리 props.handlerAddChange('overAdd', false); }; @@ -565,12 +572,12 @@ export const LaancDrawControl = props => { return true; }; + // 저장된 비행구역 데이터를 기반으로 지도에 다시 그려주기 const handlerPastDraw = () => { if (props.areaCoordList) { const objs = drawObj?.getAll().features; const areas = props.areaCoordList; if (areas.length > 0 && objs.length > 0) { - // areas -> 현재는 1개이지만 추후에 데이터가 바뀌면 여러개의 도형도 처리 가능! areas.map((area, idx) => { const paths = []; area.coordList.forEach(coord => paths.push([coord.lon, coord.lat])); @@ -639,7 +646,7 @@ export const LaancDrawControl = props => { } objId = polygonId; } - // 마커를 삭제하고 다시 그려주기 + // 마커를 삭제하고 다시 그려줌 const data = { coord: area.areaType === 'LINE' ? paths : [paths], id: objId @@ -754,8 +761,9 @@ export const LaancDrawControl = props => { return newObjId[0]; }; + // 비행구역 기본셋팅 const drawInit = () => { - const mode = mapControl.drawType; + const mode = drawType; if (mode !== 'DONE') { if (!mode || mode === 'RESET') { handlerResetMode(); @@ -790,6 +798,7 @@ export const LaancDrawControl = props => { drawObj.changeMode('simple_select'); }; + // 그리기모드 셋팅 const handlerStartMode = mode => { if (mode === 'LINE') { drawObj.changeMode('draw_line_string'); @@ -802,7 +811,6 @@ export const LaancDrawControl = props => { return ( <> - ); diff --git a/src/components/laanc/map/LaancDrawModal.js b/src/components/laanc/map/LaancDrawModal.js index c97c27d..c340ab3 100644 --- a/src/components/laanc/map/LaancDrawModal.js +++ b/src/components/laanc/map/LaancDrawModal.js @@ -1,6 +1,7 @@ import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'; export default function LaancDrawModal({ modal, handler }) { + // 드론원스탑으로 새창 바로가기 const handlerDroneOneStop = () => { window.open('https://drone.onestop.go.kr/', '드론원스탑'); handler(); diff --git a/src/components/laanc/map/LaancMapSearch.js b/src/components/laanc/map/LaancMapSearch.js index 8ec4b9d..46f0276 100644 --- a/src/components/laanc/map/LaancMapSearch.js +++ b/src/components/laanc/map/LaancMapSearch.js @@ -4,8 +4,13 @@ import { useState } from 'react'; import { flightPlanAPI } from '../../../modules/basis/flight/apis/basisFlightApi'; export default function LaancMapSearch({ mapObject }) { + // 검색어 const [query, setQuery] = useState(''); + + // 검색 결과 const [searchRes, setSearchRes] = useState([]); + + // 검색 여부 const [isSearch, setIsSearch] = useState(false); // 지역 검색 @@ -15,6 +20,7 @@ export default function LaancMapSearch({ mapObject }) { setSearchRes(res.data.items); }; + // 검색어 저장 const handlerSearchChange = e => { const { name, value } = e.target; @@ -23,12 +29,14 @@ export default function LaancMapSearch({ mapObject }) { } }; + // 지역 검색 후 엔터 키 const handlerSearchEnter = e => { if (e.key == 'Enter') { handlerSearchRes(); } }; + // 해당 좌표로 지도 이동 const handlerSearchCoord = (mapx, mapy) => { const numberString = [mapx, mapy]; const latlng = []; diff --git a/src/components/laanc/step/LaacnStep3.js b/src/components/laanc/step/LaacnStep3.js index 96c0ca8..3121f2f 100644 --- a/src/components/laanc/step/LaacnStep3.js +++ b/src/components/laanc/step/LaacnStep3.js @@ -41,10 +41,15 @@ export default function LaacnStep3({ } }; - const [centeredModal2, setCenteredModal2] = useState(false); + // 성공 모달 + const [confirmModal, setConfirmModal] = useState(false); + // 공문 모달 const [formModal, setFormModal] = useState(false); - const [numPages, setNumPages] = useState(null); // total + // total + const [numPages, setNumPages] = useState(null); + // 로그인 정보 const { user } = useSelector(state => state.authState); + // pdf 데이터 const { laancPdf } = useSelector(state => state.laancState); // PDF 다운로드 @@ -241,16 +246,16 @@ export default function LaacnStep3({ - setCenteredModal2(!centeredModal2)} + isOpen={confirmModal} + toggle={() => setConfirmModal(!confirmModal)} className='modal-dialog-centered' style={{ maxWidth: '650px', margin: '0 auto' }} > - setCenteredModal2(!centeredModal2)}> + setConfirmModal(!confirmModal)}> 비행 승인 완료 diff --git a/src/components/laanc/step/LaancStep1.js b/src/components/laanc/step/LaancStep1.js index a3c8921..a600128 100644 --- a/src/components/laanc/step/LaancStep1.js +++ b/src/components/laanc/step/LaancStep1.js @@ -39,24 +39,36 @@ export default function LaancStep1({ }) { const dispatch = useDispatch(); + // 로그인 정보 const { user } = useSelector(state => state.authState); + // 비행 구역 정보 const { areaCoordList } = useSelector(state => state.flightState); + // 일물 일출, 고도 정보, 관제권안 정보 const { laancSun, laancElev, laancArea } = useSelector( state => state.laancState ); + + // LAANC 폼 제어 const fltElevRef = useRef(null); const bufferZoneRef = useRef(null); const schFltStDtRef = useRef(null); const schFltEndDtRef = useRef(null); + + // 마운트 시 지도 표출 여부 const location = useLocation(); const queryParams = new URLSearchParams(location.search); const mapParam = queryParams.get('map'); - const [qrData, setQrData] = useState(); // qr 인증 데이터 + // qr 인증 데이터 + const [qrData, setQrData] = useState(); + // qr 팝업 const [isPopUp, setIsPopUp] = useState(false); + // 아이콘 팝오버 const [popoverCommercial, setPopoverCommercial] = useState(false); const [popoverSchFltStDt, setPopoverSchFltStDt] = useState(false); const [popoverSchFltEndDt, setPopoverSchFltEndDt] = useState(false); + + // 모달 const [isErrorModal, setIsErrorModal] = useState({ isOpen: false, title: '', diff --git a/src/components/laanc/step/LaancStep2.js b/src/components/laanc/step/LaancStep2.js index e6880e5..0939b3c 100644 --- a/src/components/laanc/step/LaancStep2.js +++ b/src/components/laanc/step/LaancStep2.js @@ -40,11 +40,17 @@ export default function LaancStep2({ 11: '25kg초과' } }; + // 약관 동의 const [isterms, setIsterms] = useState(false); + // 약관 팝업 const [isPopUp, setIsPopUp] = useState(false); + // 비행 승인 요청 데이터 const [flightData, setFlightData] = useState({}); + // 로그인 정보 const { user } = useSelector(state => state.authState); + // 약관 동의 데이터 const { termsList } = useSelector(state => state.accountState); + // pdf 데이터 const { laancPdf } = useSelector(state => state.laancState); const dispatch = useDispatch(); diff --git a/src/containers/analysis/simulator/AnalysisSimulationContainer.js b/src/containers/analysis/simulator/AnalysisSimulationContainer.js index 5f37dae..8befd73 100644 --- a/src/containers/analysis/simulator/AnalysisSimulationContainer.js +++ b/src/containers/analysis/simulator/AnalysisSimulationContainer.js @@ -15,33 +15,47 @@ let playCount = 0; let playCounts = 0; export const AnalysisSimulationContainer = props => { + // 슬라이드 모든 데이터 const { list, count, detail, searchParams, log, stcsList, stcsCount, page } = useSelector(state => state.analysisSimulatorState); + // 비행 시물레이션 데이터 const [oepnReportList, setOpenReportList] = useState(false); + // 지도 객체 const [mapObject, setMapObject] = useState(null); + // 비행 시물레이션 데이터 상세보기 const [openDetail, setOpenDetail] = useState(false); + // 선택 마커 const [selMarker, setSelMarker] = useState(null); + // 좌표 정보 const [selPolyline, setSelPolyline] = useState(null); + // 슬라이드 재생 여부 const [isPlay, setIsPlay] = useState(false); + // 드론 정보 const [info, setInfo] = useState(null); + // 슬라이드 시간 const [timeCd, setTimeCd] = useState(null); + // 슬라이드 카운터 const [sliderCount, setSliderCount] = useState(0); + // 검색 텍스트 const [searchText, setSearchText] = useState(''); + // 비행 pk 값 const [cntrlId, setCntrlId] = useState(''); + // 드론 마커 const [marker, setMarker] = useState(null); + // 카운터 초기값 const [sliderVal, setSliderVal] = useState({ maxVal: 0, minVal: 0 @@ -49,16 +63,18 @@ export const AnalysisSimulationContainer = props => { const dispatch = useDispatch(); + // 드론 갯수 const [dronLength, setDronLength] = useState(0); - + // 비행 시간 카운터 const [countArray, setCountArray] = useState([]); + // 검색 데이터 const [params, setParams] = useState({ stDate: moment().subtract(1, 'day').format('YYYY-MM-DD'), endDate: moment().subtract(0, 'day').format('YYYY-MM-DD'), search1: '' }); - // 시뮬레이션 타이머 + // 시뮬레이션 타이머 로직 useEffect(() => { if (isPlay) { const countCheck = log.map(item => @@ -95,6 +111,7 @@ export const AnalysisSimulationContainer = props => { } }, [isPlay, log]); + // useEffect(() => { if (isPlay) { setInfo({ ...log[playCount], playCount, playCounts }); @@ -102,6 +119,7 @@ export const AnalysisSimulationContainer = props => { } }, [stcsList]); + // 검색 변경 헨들러 useEffect(() => { if (oepnReportList) { if (searchParams) { @@ -113,6 +131,8 @@ export const AnalysisSimulationContainer = props => { } } }, [oepnReportList]); + + // 슬라이드 카운터 로직 useEffect(() => { if (sliderCount && sliderCount > 0) { let benear = countArray[0]; @@ -138,6 +158,7 @@ export const AnalysisSimulationContainer = props => { } }, [sliderCount]); + // 슬라이드 카운터 초기화 useEffect(() => { playCount = 0; playCounts = 0; @@ -163,6 +184,7 @@ export const AnalysisSimulationContainer = props => { // let maxDate; }, [log]); + // 검색 헨들러 const handlerSearch = search1 => { setParams({ ...params, search1 }); dispatch( @@ -178,10 +200,12 @@ export const AnalysisSimulationContainer = props => { dispatch(Actions.log.request(id)); }; + // const handlerStcsSearch = id => { dispatch(Actions.stcs.request(id)); }; + // 검색 const handlerInput = (type, val) => { if (type === 'search1') { setParams({ ...params, search1: val }); @@ -197,6 +221,7 @@ export const AnalysisSimulationContainer = props => { } }; + // 상세보기 const handlerDetail = id => { // setOpenReportList(false); handlerDetailSearch(id); @@ -206,19 +231,25 @@ export const AnalysisSimulationContainer = props => { setCntrlId(id); }; + + // 로그아웃 const handlerLogout = () => { dispatch(Action.logout.request()); }; + + // 비행 시물레이션 데이터 닫기 const handlerDetailClose = () => { setOpenDetail(false); }; + // 비행 시물레이션 데이터 호출 const handlerPageList = useCallback(() => { dispatch( Actions.list.request({ searchParams: { ...params }, page: page + 1 }) ); }, [params, list, page]); + // 비행 시물레이션 데이터 모달 헨들러 const handlerOpenReportList = useCallback( val => { setOpenReportList(val); diff --git a/src/containers/laanc/LaancContainer.js b/src/containers/laanc/LaancContainer.js index 5860461..6e0d4d7 100644 --- a/src/containers/laanc/LaancContainer.js +++ b/src/containers/laanc/LaancContainer.js @@ -13,11 +13,17 @@ import LaancGrid from '../../components/laanc/list/LaancGrid'; export default function LaancContainer() { const dispatch = useDispatch(); - const location = useLocation(); - + // map 컴포넌트 표출 여부 const [currentParm, setCurrentParm] = useState(false); + //LAANC 신청하기 모달 const [disabledAnimation, setDisabledAnimation] = useState(false); +<<<<<<< HEAD const [isSearch, setIsSearch] = useState(false); +======= + + // 마운트 시 지도 표출 여부 + const location = useLocation(); +>>>>>>> 1ed9d9e3865eef0d42bac8f02dddb2a221ff8d58 const queryParams = new URLSearchParams(location.search); const mapParam = queryParams.get('map'); @@ -30,6 +36,7 @@ export default function LaancContainer() { setDisabledAnimation(mapParam != 'true' ? false : true); }, [location]); +<<<<<<< HEAD // Laanc 신청 이후 자동 검색 useEffect(() => { if (disabledAnimation) { @@ -37,6 +44,8 @@ export default function LaancContainer() { } else setIsSearch(true); }, [disabledAnimation]); +======= +>>>>>>> 1ed9d9e3865eef0d42bac8f02dddb2a221ff8d58 // LAANC 신청하기 버튼 클릭 헨들러 const handleApply = () => { dispatch(drawTypeChangeAction('')); diff --git a/src/containers/laanc/LaancPlanContainer.js b/src/containers/laanc/LaancPlanContainer.js index 3941ea6..14761b0 100644 --- a/src/containers/laanc/LaancPlanContainer.js +++ b/src/containers/laanc/LaancPlanContainer.js @@ -17,11 +17,20 @@ export default function LaancPlanContainer({ }) { const dispatch = useDispatch(); + // 비행 구역 정보 + const { areaCoordList } = useSelector(state => state.flightState); + // 로그인 정보 const { user } = useSelector(state => state.authState); - + // 관제권안 정보,고도 정보 + const { laancArea, laancElev } = useSelector(state => state.laancState); + // laanc step const [step, setStep] = useState(1); + // laanc 초기값 const [detailData, setDetailData] = useState(initFlightBas.initDetail); + // 비행 구역 보달 const [centeredModal, setCenteredModal] = useState(false); + + // 모달 const [isErrorModal, setIsErrorModal] = useState({ isOpen: false, title: '', @@ -54,6 +63,309 @@ export default function LaancPlanContainer({ setStep(step); }; + // 날씨 핸들러 + const handlerWeather = () => { + setFormModal(!formModal); + }; + + // 비행계획서 작성 핸들러 + const handleChange = ({ name, value, type, index, pIndex }) => { + const arrName = `${type}List`; + + switch (type) { + case 'coord': + setDetailData(prevState => { + return { + ...prevState, + areaList: [ + { + ...prevState.areaList[0], + + coordList: value + } + ] + }; + }); + break; + case 'area': + if (name === 'fltMethod' && value != '직접입력') { + setDetailData(prevState => { + const arr = [...prevState[arrName]]; + const updateData = { + ...prevState[arrName][0], + [name]: value, + fltMothoeRm: '' + }; + arr[0] = updateData; + return { + ...prevState, + [arrName]: arr + }; + }); + } else if ( + detailData.areaList[0].areaType === 'LINE' || + name === 'bufferZone' + ) { + setDetailData(prevState => { + const arr = [...prevState[arrName]]; + const prevBufferZone = prevState[arrName][0].bufferZone; + const updateData = { + ...prevState[arrName][0], + [name]: value, + concatBufferZone: prevBufferZone + }; + arr[0] = updateData; + return { + ...prevState, + [arrName]: arr + }; + }); + } else { + setDetailData(prevState => { + const arr = [...prevState[arrName]]; + const updateData = { + ...prevState[arrName][0], + [name]: value + }; + arr[0] = updateData; + return { + ...prevState, + [arrName]: arr + }; + }); + } + break; + case 'pilot': + case 'arcrft': + { + setDetailData(prevState => { + const arr = [...prevState[arrName]]; + const updateData = { + ...prevState[arrName][0], + [name]: value + }; + arr[0] = updateData; + return { + ...prevState, + [arrName]: arr + }; + }); + } + break; + case 'plan': + default: + setDetailData(prevState => ({ + ...prevState, + [name]: value + })); + break; + } + }; + + // 스텝 1 다음 버튼 이벤트 + const handlerNext = () => { + // 시작일자 + const schFltStDt = moment(detailData.schFltStDt, 'YYYY-MM-DD HH:mm:ss'); + // 종료일자 + const schFltEndDt = moment(detailData.schFltEndDt, 'YYYY-MM-DD HH:mm:ss'); + + const currentDate = moment(); // 현재 날짜와 시간을 가져옵니다. + + const validateAircraftWeightCode = + !detailData.arcrftList[0].arcrftTypeCd && + (detailData.commercial === 'COMMERCIAL' || + detailData.arcrftList[0].arcrftWghtCd == '9' || + detailData.arcrftList[0].arcrftWghtCd == '10' || + detailData.arcrftList[0].arcrftWghtCd == '11'); + + const validateidntfNumCode = + !detailData.arcrftList[0].idntfNum && + (detailData.commercial === 'COMMERCIAL' || + detailData.arcrftList[0].arcrftWghtCd == '9' || + detailData.arcrftList[0].arcrftWghtCd == '10' || + detailData.arcrftList[0].arcrftWghtCd == '11'); + + if (!detailData.fltType) { + setIsErrorModal({ + isOpen: true, + title: '필수값 입력 오류', + desc: '비행 종류(상업/비상업)를 선택해주세요.' + }); + return false; + } else if ( + !schFltStDt.isAfter(currentDate) || + !schFltEndDt.isAfter(currentDate) + ) { + setIsErrorModal({ + isOpen: true, + title: '필수값 입력 오류', + desc: '비행 일자가 이미 지난 일자입니다.' + }); + return false; + } else if (schFltStDt.isAfter(schFltEndDt)) { + setIsErrorModal({ + isOpen: true, + title: '필수값 입력 오류', + desc: '비행일자를 확인해주세요.' + }); + return false; + } else if (schFltStDt.format('A h:mm') === 'PM 11:00') { + setIsErrorModal({ + isOpen: true, + title: '특별 비행', + desc: ( + <> + 야간 비행은 특별 비행에 해당됩니다. +
+ 특별 비행의 경우 드론원스톱을 통해서 신청해주시기 바랍니다. + + ) + }); + return false; + } else if (schFltStDt.format('A h:mm') === 'PM 5:00') { + setIsErrorModal({ + isOpen: true, + title: '비행구역 및 비행일자 중복', + desc: ( + <> + 설정하신 비행구역 및 비행시간에 이미 승인완료된 신청건이 있습니다. +
다시 설정 부탁드립니다. + + ) + }); + return false; + } else if (!detailData.fltPurpose) { + setIsErrorModal({ + isOpen: true, + title: '필수값 입력 오류', + desc: '비행목적을 선택해 주세요.' + }); + + return false; + } else if ( + !detailData.areaList[0].fltElev || + detailData.areaList[0].fltElev === 0 + ) { + setIsErrorModal({ + isOpen: true, + title: '필수값 입력 오류', + desc: '고도를 입력해 주세요.' + }); + + return false; + } else if (!detailData.areaList[0].bufferZone) { + setIsErrorModal({ + isOpen: true, + title: '필수값 입력 오류', + desc: '반경을 입력해 주세요.' + }); + + return false; + } else if ( + detailData.areaList[0].concatBufferZone != + detailData.areaList[0].bufferZone && + detailData.areaList[0].areaType === 'LINE' + ) { + setIsErrorModal({ + isOpen: true, + title: '필수값 입력 오류', + desc: <>적용 버튼을 누르지 않고 값을 변경 할 수 없습니다. + }); + // handleChange({ + // type: 'area', + // name: 'bufferZone', + // value: detailData.areaList[0].concatBufferZone + // }); + } else if (!detailData.areaList[0].fltMethod) { + setIsErrorModal({ + isOpen: true, + title: '필수값 입력 오류', + desc: '비행방식를 입력해 주세요.' + }); + + return false; + } else if ( + detailData.areaList[0].fltMethod === '00' && + !detailData.areaList[0].fltMothoeRm + ) { + // 비행 방식 직접 입력칸 활성화 후 작성 시 조건문 + setIsErrorModal({ + isOpen: true, + title: '필수값 입력 오류', + desc: '비행방식을 입력해 주세요.' + }); + return false; + } else if (validateAircraftWeightCode) { + setIsErrorModal({ + isOpen: true, + title: '필수값 입력 오류', + desc: '기체 종류를 입력해 주세요.' + }); + + return false; + } else if (validateidntfNumCode) { + setIsErrorModal({ + isOpen: true, + title: '필수값 입력 오류', + desc: '기체 신고 번호를 입력해 주세요.' + }); + return false; + } else { + handlerLaanc(); + } + }; + + // 비행 구역 적용 버튼 핸들러 + const handlerBufferApply = async () => { + if (areaCoordList) { + if (areaCoordList[0].coordList.length > 0) { + // dispatch(LaancAction.LAANC_ALTITUDE.request(detailData.areaList)); + dispatch(LaancAction.LAANC_VALID_AREA.request(detailData.areaList)); + + const array = []; + const copy = { ...areaCoordList[0] }; + copy.bufferZone = detailData.areaList[0].bufferZone; + array.push(copy); + + dispatch(FLIGHT_PLAN_AREA_BUFFER_LIST.request(array)); + + try { + const elev = await axios.post( + `api/bas/laanc/valid/elev`, + detailData.areaList + ); + + if (elev.data[0] === 0) { + // dispatch(AREA_DETAIL_INIT()); + // dispatch(AreaAction.AREA_DETAIL_INIT()); + // dispatch(drawTypeChangeAction('')); + // dispatch(LaancAction.LAANC_APPROVAL_INIT()); + setIsErrorModal({ + title: '비행 불가 지역', + desc: ( + <> + 설정하신 비행구역 중 허용고도가 0m인 구역이 있습니다. +
+ 버퍼존을 다시 확인해주시기 바랍니다. + + ), + isOpen: true + }); + } + dispatch(LaancAction.LAANC_ALTITUDE.success(elev.data)); + } catch (error) { + { + setIsErrorModal({ + isOpen: true, + title: '오류', + desc: '처리중 오류가 발생하였습니다' + }); + } + } + } + } + }; + // Laanc 승인 요청 취소 버튼 헨들러 const handlerLaancClose = () => { setStep(1); diff --git a/src/utility/DrawUtil.js b/src/utility/DrawUtil.js index 87553f1..19cb367 100644 --- a/src/utility/DrawUtil.js +++ b/src/utility/DrawUtil.js @@ -2,6 +2,7 @@ import * as turf from '@turf/turf'; import mapboxgl from 'mapbox-gl'; import 'mapbox-gl/dist/mapbox-gl.css'; +// geojson Feature 형식으로 반환 export const InitFeature = (type, id) => { return { type: 'Feature', @@ -43,6 +44,13 @@ export const CalculateDistance = (mouse, center) => { return distance; }; +// 미터 반환(m붙여서) +export const fromMetersToText = meters => { + meters = meters || 0; + const text = parseFloat(meters.toFixed(1)) + 'm'; + return text; +}; + // 두 좌표 간의 중간 지점 좌표 반환 export const handlerGetMidPoint = (dis1, dis2) => { return [(dis1[0] + dis2[0]) / 2, (dis1[1] + dis2[1]) / 2]; @@ -63,13 +71,6 @@ export const handlerGetHtmlContent = (distance, id) => { ); }; -// 미터 반환(m붙여서) -export const fromMetersToText = meters => { - meters = meters || 0; - const text = parseFloat(meters.toFixed(1)) + 'm'; - return text; -}; - // circle 360도 좌표 반환 export const handlerGetCircleCoord = (center, distance) => { const options = { @@ -183,25 +184,6 @@ export const layerWayPoint = source => { }; }; -export const layerGuideLine = source => { - return { - id: 'guideline', - type: 'line', - source: source, - layout: { - 'line-cap': 'round', - 'line-join': 'round' - }, - paint: { - 'line-color': '#283046', - 'line-width': 2, - 'line-opacity': 0.5, - 'line-dasharray': [5, 5] - }, - filter: ['==', ['get', 'id'], 'guideline'] - }; -}; - export const layerPolyline = source => { return { id: 'polyline', diff --git a/src/views/control/alarm/ControlAlarmDetail.js b/src/views/control/alarm/ControlAlarmDetail.js index b7c1e68..ccf0753 100644 --- a/src/views/control/alarm/ControlAlarmDetail.js +++ b/src/views/control/alarm/ControlAlarmDetail.js @@ -1,56 +1,56 @@ -import { useState, useEffect } from 'react'; -import { Button, Modal, ModalHeader, ModalBody, ModalFooter, Card } from 'reactstrap' +import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap'; -const ControlAlarmDetail = ({ historyModal, setHistoryModal, controlGpWarnLog }) => { - return ( - setHistoryModal(!historyModal)} - className='modal-dialog-centered historyModal' - > - setHistoryModal(!historyModal)}> -
- {controlGpWarnLog?.idntfNum} - 알림내역 -
-
+const ControlAlarmDetail = ({ + historyModal, + setHistoryModal, + controlGpWarnLog +}) => { + return ( + setHistoryModal(!historyModal)} + className='modal-dialog-centered historyModal' + > + setHistoryModal(!historyModal)}> +
+ {controlGpWarnLog?.idntfNum} + 알림내역 +
+
- - - - - - - - - {controlGpWarnLog ? - controlGpWarnLog.map((p, i) => { - return ( - - - - - - - ) - }) - : - - - - } -
번호식별번호날짜내용
{i + 1}{p.idntfNum}{p.createDt}{p.warnType}
데이터가 없습니다.
-
- - - -
- ) -} + + + + + + + + + {controlGpWarnLog ? ( + controlGpWarnLog.map((p, i) => { + return ( + + + + + + + ); + }) + ) : ( + + + + )} +
번호식별번호날짜내용
{i + 1}{p.idntfNum}{p.createDt}{p.warnType}
데이터가 없습니다.
+
+ + + +
+ ); +}; -export default ControlAlarmDetail; \ No newline at end of file +export default ControlAlarmDetail; diff --git a/src/views/control/alarm/ControlAlarmList.js b/src/views/control/alarm/ControlAlarmList.js index 8701e72..f57a796 100644 --- a/src/views/control/alarm/ControlAlarmList.js +++ b/src/views/control/alarm/ControlAlarmList.js @@ -1,175 +1,151 @@ import { useEffect, useState } from 'react'; import { X } from 'react-feather'; import { useDispatch, useSelector } from 'react-redux'; -import { controlGpArcrftWarnAction, controlGpLogAction } from '../../../modules/control/gp/actions/controlGpAction'; +import { controlGpLogAction } from '../../../modules/control/gp/actions/controlGpAction'; import ControlAlarmDetail from './ControlAlarmDetail'; import { Badge } from 'reactstrap'; const ControlAlarmList = props => { - const dispatch = useDispatch(); - - const [historyModal, setHistoryModal] = useState(false); + const dispatch = useDispatch(); + // 비정상상황 상세 히스토리 모달 + const [historyModal, setHistoryModal] = useState(false); - const { controlGpList } = useSelector(state => state.controlGpState); - const { controlGpArcrftWarnList } = useSelector(state => state.controlGpLogState); - const { controlGpWarnLog } = useSelector(state => state.controlGpLogState); - const { objectId, isClickObject } = useSelector(state => state.controlMapReducer); + // 비정상상황 상세 히스토리 + const { controlGpWarnLog } = useSelector(state => state.controlGpLogState); - - const [total, setTotal] = useState({ - totalDroneCnt: 0, - totalWarnCnt: 0, - warnList: [] - }); + // 비정상상황 기체 목록 + const { controlGpArcrftWarnList } = useSelector( + state => state.controlGpLogState + ); - const handleWarnDetail = (cntrlId) => { - setHistoryModal(prev => !prev); + // 클릭한 기체 Id, 비행중인 기체 클릭 여부 + const { objectId, isClickObject } = useSelector( + state => state.controlMapReducer + ); - dispatch(controlGpLogAction.request({id : cntrlId})); - } + // 전체 드론, 비정상 드론 개수 + const [total, setTotal] = useState({ + totalDroneCnt: 0, + totalWarnCnt: 0, + warnList: [] + }); - useEffect(() => { - if(isClickObject) { - props.setOpenAlarmList(false); - } + // 비정상상황 상세 히스토리 모달 표출 + const handleWarnDetail = cntrlId => { + setHistoryModal(prev => !prev); + dispatch(controlGpLogAction.request({ id: cntrlId })); + }; - }, [objectId, isClickObject]) + // 비행중인 기체 클릭 시 비정상상황 사이드메뉴 닫힘 + useEffect(() => { + if (isClickObject) { + props.setOpenAlarmList(false); + } + }, [objectId, isClickObject]); - useEffect(() => { - if(controlGpArcrftWarnList) { - let totalWarnCnt = 0; + // 비정상상황 기체 개수 계산 + useEffect(() => { + if (controlGpArcrftWarnList) { + let totalWarnCnt = 0; - if(controlGpArcrftWarnList.length > 0) { - controlGpArcrftWarnList.forEach(warn => { - totalWarnCnt += warn.warnCount; - }); - } + if (controlGpArcrftWarnList.length > 0) { + controlGpArcrftWarnList.forEach(warn => { + totalWarnCnt += warn.warnCount; + }); + } - setTotal(total => { - return { - totalDroneCnt : controlGpArcrftWarnList.length, - totalWarnCnt : totalWarnCnt, - warnList : controlGpArcrftWarnList - } - }) - } + setTotal(total => { + return { + totalDroneCnt: controlGpArcrftWarnList.length, + totalWarnCnt: totalWarnCnt, + warnList: controlGpArcrftWarnList + }; + }); + } + }, [controlGpArcrftWarnList]); - }, [controlGpArcrftWarnList]); - - return ( -
-
-
-

실시간 비정상 알림 정보

- -
-
-
-
-
-
드론 현황
-
- - {total? total.totalDroneCnt: 0}대 비행 중 - -
-
-
-
-
-
비정상 알림 전체
-
- - {total? total.totalWarnCnt : 0}건 - -
-
-
-
+ return ( +
+
+
+

실시간 비정상 알림 정보

+ +
+
+
+
+
+
드론 현황
+
+ + {total ? total.totalDroneCnt : 0}대 비행 중 +
-
-
-
-

알림 목록

+
+
+
+
+
비정상 알림 전체
+
+ + {total ? total.totalWarnCnt : 0}건 +
- {total?.warnList.map((warn, i) => { - const warnContent = warn.warnType === 'PLAN' ? '비행 경로 이탈' : '비정상 상황 발생' +
+
+
+
+
+
+
+

알림 목록

+
+ {total?.warnList.map((warn, i) => { + const warnContent = + warn.warnType === 'PLAN' ? '비행 경로 이탈' : '비정상 상황 발생'; - return ( -
handleWarnDetail(warn.cntrlId)}> -
-
-
-
{warn.idntfNum}
-
{warn.occurDt ? warn.occurDt : '-'}
-
-
-
{warnContent ? warnContent : '-'}
-
{warn.warnCount ? warn.warnCount : '-'}건
-
-
-
-
- ) - })} - {/*
-
-
-
-
PAV-001
-
2022. 09. 02 10:00:30
-
-
-
비행 경로 이탈
-
22건
-
-
-
-
-
-
-
-
-
PAV-002
-
2022. 09. 02 11:23:52
-
-
-
비행 경로 이탈
-
10건
-
-
-
-
-
-
-
-
-
PAV-003
-
-
-
-
-
-
-
0건
-
-
-
-
*/} + return ( +
handleWarnDetail(warn.cntrlId)} + > +
+
+
+
{warn.idntfNum}
+
+ {warn.occurDt ? warn.occurDt : '-'} +
+
+
+
+ {warnContent ? warnContent : '-'} +
+
+ {warn.warnCount ? warn.warnCount : '-'}건 +
+
+
+
+ ); + })} +
- -
- ); + +
+ ); }; export default ControlAlarmList; diff --git a/src/views/control/alarm/ControlAlarmNotice.js b/src/views/control/alarm/ControlAlarmNotice.js deleted file mode 100644 index 9c01ad4..0000000 --- a/src/views/control/alarm/ControlAlarmNotice.js +++ /dev/null @@ -1,45 +0,0 @@ -import { Bell, ChevronDown, ChevronUp } from "react-feather"; -import { ReactComponent as DroneMenuIcon } from '../../../assets/images/drone_menu_icon.svg'; - -const ControlAlarmNotice = () => { - {} - return( - -
- {/*
-
- -
-
-
-
- 2021-06-17 12:00:00AVSF123 장애물 - 지역에 접근하였습니다111. -
-
- 2021-06-30 13:00:00AVSF123 - 비행금지구역에 접근하였습니다. -
-
- 2021-08-20 14:00:00AVSF123 - 국립공원구역에 접근하였습니다. -
-
-
-
- - -
-
*/} - -
- - - ) -} - -export default ControlAlarmNotice; diff --git a/src/views/control/main/ControlMain.js b/src/views/control/main/ControlMain.js index 24fd640..4a0fb6f 100644 --- a/src/views/control/main/ControlMain.js +++ b/src/views/control/main/ControlMain.js @@ -11,7 +11,6 @@ import { Cloud, CloudRain, CloudSnow, - Moon, Grid } from 'react-feather'; @@ -19,7 +18,6 @@ import { AiOutlinePoweroff } from 'react-icons/ai'; import { IoAlertOutline } from 'react-icons/io5'; import { ReactComponent as DroneMenuIcon } from '../../../assets/images/drone_menu_icon.svg'; import { Card } from 'reactstrap'; -import ControlAlarmNotice from '../alarm/ControlAlarmNotice'; import ControlReportList from '../report/ControlReportList'; import ControlReportDetail from '../report/ControlReportDetail'; import ControlAlarmList from '../alarm/ControlAlarmList'; @@ -28,71 +26,51 @@ import WebsocketClient from '../../../components/websocket/WebsocketClient'; import { useDispatch, useSelector } from 'react-redux'; import { controlweatherAction } from '../../../modules/control/gp/actions/controlGpAction'; import * as Actions from '../../../modules/account/login/actions/authAction'; -import { - ctrlDrawTypeChangeAction, - objectUnClickAction -} from '../../../modules/control/map/actions/controlMapActions'; +import { objectUnClickAction } from '../../../modules/control/map/actions/controlMapActions'; const ControlMain = () => { const dispatch = useDispatch(); + const history = useHistory(); + // 비행중인 기체 클릭 여부 const { isClickObject } = useSelector(state => state.controlMapReducer); - const { controlGpList, controlGroupAuthInfo } = useSelector( - state => state.controlGpState - ); + + // 비행중인 기체 정보 + const { controlGpList } = useSelector(state => state.controlGpState); + + // 기체 상세 정보 const { controlDetail, controlWheather } = useSelector( state => state.controlGpDtlState ); + + // 드론 기체 갯수 (드론 + uam) const { controlGpCountDrone, controlGpCountFlight } = useSelector( state => state.controlGpCountState ); - // pav박람회 -> uam, 드론 구별을 위한 임시 코드 - // (이 작업으로 고도화 하려면 추후에 서버에서 uam타입을 새로 더 받아 작업해야 함) + // 드론, uam 기체 갯수 const [droneCount, setDroneCount] = useState(0); const [uamCount, setUamCount] = useState(0); + // 비정상상황 여부 const [alarm, setAlarm] = useState(false); - const { user } = useSelector(state => state.authState); - const [oepnReportList, setOpenReportList] = useState(false); - // const [openReportDetail, setOpenReportDetail] = useState(false); - // const [openWeatherList, setOpenWeatherList] = useState(false); - const [openAlarmList, setOpenAlarmList] = useState(false); + // 오른쪽 사이드 메뉴 표출 여부 const [openSetting, setOpenSetting] = useState(true); - const history = useHistory(); - const openMenu = val => { - if (val === 'reportList') { - setOpenReportList(true); - // setOpenReportDetail(false); - // setOpenWeatherList(false); - setOpenAlarmList(false); - } else if (val === 'weatherList') { - setOpenReportList(false); - // setOpenReportDetail(false); - // setOpenWeatherList(true); - setOpenAlarmList(false); - } else if (val === 'alarmList') { - dispatch(objectUnClickAction()); - - setOpenReportList(false); - // setOpenReportDetail(false); - // setOpenWeatherList(false); - setOpenAlarmList(true); - - setAlarm(false); - } - }; + // 왼쪽 드론 정보 사이드 메뉴 표출 여부 + const [oepnReportList, setOpenReportList] = useState(false); - // const openReportDetailParam = val => { - // setOpenReportDetail(true); - // }; + // 왼쪽 드론 비정상상황 알림 사이드 메뉴 표출 여부 + const [openAlarmList, setOpenAlarmList] = useState(false); - const handlerLogout = () => { - dispatch(Actions.logout.request()); + // 김포공항 좌표 + const rq = { + nx: 37.558522, + ny: 126.793722 }; + // 드론 비정상상황일 시 왼쪽 사이드 메뉴 알람 표시 아이콘 변경 useEffect(() => { if (controlGpList) { const warnGps = controlGpList.find(gps => { @@ -105,6 +83,7 @@ const ControlMain = () => { } }, [controlGpList]); + // 비행중인 기체 클릭 시 열려있는 사이드 메뉴 닫기 useEffect(() => { if (isClickObject) { setOpenReportList(false); @@ -112,6 +91,7 @@ const ControlMain = () => { } }, [isClickObject]); + // 드론, uam 기체 갯수 계산 useEffect(() => { if (controlGpCountDrone) { const uamCnt = controlGpCountDrone.filter(i => @@ -126,19 +106,43 @@ const ControlMain = () => { } }, [controlGpCountDrone]); + // 김포공항 날씨 API호출 + useEffect(() => { + dispatch(controlweatherAction.request(rq)); + }, []); + + // 화면 왼쪽 사이드 메뉴 오픈 시 다른 메뉴 닫기 + const openMenu = val => { + console.log(val, '--'); + if (val === 'reportList') { + setOpenReportList(true); + setOpenAlarmList(false); + } else if (val === 'weatherList') { + setOpenReportList(false); + setOpenAlarmList(false); + } else if (val === 'alarmList') { + dispatch(objectUnClickAction()); + + setOpenReportList(false); + setOpenAlarmList(true); + + setAlarm(false); + } + }; + + // 로그아웃 + const handlerLogout = () => { + dispatch(Actions.logout.request()); + }; + + // 드론 상세정보 창 닫기 const handlerClose = () => { setOpenReportList(true); dispatch(objectUnClickAction()); }; - //날씨 API - const rq = { - nx: 37.558522, - ny: 126.793722 - }; - useEffect(() => { - dispatch(controlweatherAction.request(rq)); - }, []); - function weathericon() { + + // 김포공항 날씨 아이콘 설정 + const weathericon = () => { if (controlWheather) { let wheatherDetail = controlWheather.items.item; let skyDetail = wheatherDetail[6].fcstValue; @@ -150,24 +154,10 @@ const ControlMain = () => { return ; } else return ; } - } - - const handlerDrawType = val => { - dispatch(ctrlDrawTypeChangeAction(val)); - }; - - const ThemeToggler = () => { - if (skin === 'dark') { - return setSkin('light')} />; - } else { - return setSkin('dark')} />; - } }; return ( <> - -

@@ -283,12 +273,6 @@ const ControlMain = () => {
드론 - {/* {controlGpList ? controlGpList.length : 0} */} - {/* - {controlGpCountDrone?.length > 0 - ? controlGpCountDrone?.length - : 0} - */} {droneCount}
@@ -297,7 +281,6 @@ const ControlMain = () => {
항공기 - {/* 2147대 */} {controlGpCountFlight?.length > 0 ? controlGpCountFlight?.length @@ -307,30 +290,10 @@ const ControlMain = () => {
- {/*
- -
- 화재경보 -
-
-
- handlerDrawType('CIRCLE')}> - 화재구역설정 - -
-
- handlerDrawType('RESET')}>초기화 -
-
-
-
*/}

{oepnReportList ? ( - + ) : (
)} @@ -339,11 +302,6 @@ const ControlMain = () => { ) : (
)} - {/* {openWeatherList ? ( - - ) : ( -
- )} */} {openAlarmList ? ( diff --git a/src/views/control/report/ControlReportDetail.js b/src/views/control/report/ControlReportDetail.js index 7ce80f7..732c48f 100644 --- a/src/views/control/report/ControlReportDetail.js +++ b/src/views/control/report/ControlReportDetail.js @@ -1,45 +1,51 @@ import moment from 'moment'; -import React, { useMemo } 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'; import uam_img from '../../../assets/images/uam_img.jpg'; import drone_yellow from '../../../assets/images/drone_yellow.png'; -import { IMG_PATH } from '../../../configs/constants'; -import { objectUnClickAction } from '../../../modules/control/map/actions/controlMapActions'; import { GET_ARCTFT_TYPE_CD, GET_WGHT_TYPE_CD } from '../../../utility/CondeUtil'; -import { - controlGpLogAction, - controlweatherAction -} from '../../../modules/control/gp'; +import { controlGpLogAction } from '../../../modules/control/gp'; import ControlAlarmDetail from '../alarm/ControlAlarmDetail'; -import axios from '../../../modules/utils/customAxiosUtil'; import { Navigation2, - Search, Compass, Sun, Cloud, CloudRain, CloudSnow } from 'react-feather'; -import { WHEATHER_KEY } from '../../../configs/constants'; import { Table } from 'reactstrap'; + const ControlReportDetail = props => { const dispatch = useDispatch(); + + // 비정상상황 모달 const [historyModal, setHistoryModal] = useState(false); + // 기체 상세정보 const { controlGpDetail, controlDetail } = useSelector( state => state.controlGpDtlState ); - //const { controlWheather } = useSelector(state => state.ControlGpWeatherState); + + // 비정상상황 히스토리 내역 const { controlGpWarnLog } = useSelector(state => state.controlGpLogState); - function weathericon() { + // 해당 드론의 비정상상황 알림내역 불러옴 + useEffect(() => { + if (historyModal) { + if (controlGpDetail) { + dispatch(controlGpLogAction.request({ id: controlGpDetail.controlId })); + } + } + }, [historyModal]); + + // 날씨 아이콘 표출 + const weathericon = () => { if (controlDetail) { let wheatherDetail = controlDetail.items.item; let skyDetail = wheatherDetail[6].fcstValue; @@ -51,16 +57,9 @@ const ControlReportDetail = props => { return ; } else return ; } - } - - useEffect(() => { - if (historyModal) { - if (controlGpDetail) { - dispatch(controlGpLogAction.request({ id: controlGpDetail.controlId })); - } - } - }, [historyModal]); + }; + // 상세정보에 내역이 없으면 -로 표출 const nullMessage = val => { if (val) { return val; @@ -68,6 +67,7 @@ const ControlReportDetail = props => { return '-'; } }; + return (
@@ -76,7 +76,6 @@ const ControlReportDetail = props => {
- {/* {controlDetail?.imageUrl ? ( - - ) : ( - - )} */} {controlGpDetail?.objectId.includes('UAM') ? ( ) : ( @@ -138,18 +132,6 @@ const ControlReportDetail = props => { {GET_ARCTFT_TYPE_CD(controlDetail?.arcrftTypeCd)}
- {/*
-
배터리 잔량
-
- {controlGpDetail?.betteryLevel} % -
-
-
-
배터리 전압
-
- {controlGpDetail?.betteryVoltage} volt -
-
*/}
@@ -177,12 +159,6 @@ const ControlReportDetail = props => { : '-'}
- {/*
-
현재위치
-
- 인천광역시 부평구 안남로 272 -
-
*/}
속도
@@ -207,25 +183,12 @@ const ControlReportDetail = props => { : '-'}
- {/*
-
비행거리
-
- {nullMessage(controlGpDetail?.moveDistance)}{' '} - {controlGpDetail?.moveDistanceType} -
-
*/}
헤딩 방위각
{nullMessage(controlGpDetail?.heading)}
- {/*
-
상태
-
- {nullMessage(controlGpDetail?.dronStatus)} -
-
*/}
위치정보 수신 시간
@@ -248,10 +211,6 @@ const ControlReportDetail = props => {
- {/*
-
소속기관
-
팔네트웍스
-
*/}
담당자 이름
diff --git a/src/views/control/report/ControlReportList.js b/src/views/control/report/ControlReportList.js index 5dd5d63..6fd9459 100644 --- a/src/views/control/report/ControlReportList.js +++ b/src/views/control/report/ControlReportList.js @@ -3,27 +3,24 @@ import { useState } from 'react'; import { Search, X } from 'react-feather'; import { useDispatch, useSelector } from 'react-redux'; import { Badge, Button, Input, InputGroup } from 'reactstrap'; -import { - controlGpDtlAction, - controlGpFlightPlanAction -} from '../../../modules/control/gp'; +import { controlGpDtlAction } from '../../../modules/control/gp'; import { objectClickAction } from '../../../modules/control/map/actions/controlMapActions'; -import { NavLink } from 'react-router-dom'; const ControlReportList = props => { + const dispatch = useDispatch(); + + // 비행중인 기체 정보 리스트 const { controlGpList } = useSelector(state => state.controlGpState); - const [filterId, setFilterId] = useState(''); - const dispatch = useDispatch(); + // 검색한 식별번호 + const [filterId, setFilterId] = useState(''); + // 기체 상세정보 표출 const handlerDetail = item => { dispatch(objectClickAction(item.controlId)); dispatch(controlGpDtlAction.request(item.controlId)); - // dispatch(controlGpFlightPlanAction.request(item.objectId)); }; - // useEffect(() => {}, [filterId]); - return (
@@ -97,34 +94,6 @@ const ControlReportList = props => { {item.dronStatus ? item.dronStatus : '-'}
- - {item.objectId.includes('NAMWON') ? ( -
-
- - 실시간 영상보기 - -
-
- ) : ( - <> - )} - - {/*
- -
*/}
); diff --git a/src/views/control/setting/ControlSetting.js b/src/views/control/setting/ControlSetting.js index 162ef1d..60b1ef6 100644 --- a/src/views/control/setting/ControlSetting.js +++ b/src/views/control/setting/ControlSetting.js @@ -4,15 +4,17 @@ import { Button, ButtonGroup, CustomInput } from 'reactstrap'; import * as Actions from '../../../modules/menu/actions/menuAction'; import { areaClickAction, - mapTypeChangeAction, - sensorClickAction + mapTypeChangeAction } from '../../../modules/control/map/actions/controlMapActions'; const ControlSetting = props => { const dispatch = useDispatch(); const history = useHistory(); + + // 지도, 지도타입, 공역 타입 컨트롤 const mapControl = useSelector(state => state.controlMapReducer); + // 지도 유형 변경 const handlerMapType = val => { if (val === mapControl.mapType) return; if (val === 'TERRAIN') { @@ -35,24 +37,16 @@ const ControlSetting = props => { dispatch(mapTypeChangeAction(val)); }; + // 공역 표출 const handlerAreaClick = val => { dispatch(areaClickAction(val)); }; - const handlerSensorClick = (val, isChecked) => { - if (isChecked) { - dispatch(sensorClickAction(val)); - } else { - dispatch(sensorClickAction('')); - } - }; - return (

지도유형

- {/* */}
@@ -270,103 +264,8 @@ const ControlSetting = props => {
- {/*
-
-

환경지표

-
-
-
-
-
-
- 미세먼지(DUST) -
-
- handlerSensorClick('dust', e.target.checked)} - className='custom-control-primary' - type='switch' - id='sensorDust' - name='sensorDust' - inline - checked={mapControl.sensor === 'dust'} - // defaultChecked={mapControl.sensor === 'dust'} - /> -
-
-
-
- 오존(O3) -
-
- handlerSensorClick('o3', e.target.checked)} - className='custom-control-primary' - type='switch' - id='sensorO3' - name='sensorO3' - inline - checked={mapControl.sensor === 'o3'} - // defaultChecked={mapControl.sensor === 'o3'} - /> -
-
-
-
- 이산화질소(No2) -
-
- handlerSensorClick('no2', e.target.checked)} - className='custom-control-primary' - type='switch' - id='sensorNo2' - name='sensorNo2' - inline - checked={mapControl.sensor === 'no2'} - // defaultChecked={mapControl.sensor === 'no2'} - /> -
-
-
-
- 일산화탄소(Co) -
-
- handlerSensorClick('co', e.target.checked)} - className='custom-control-primary' - type='switch' - id='sensorCo' - name='sensorCo' - inline - checked={mapControl.sensor === 'co'} - // defaultChecked={mapControl.sensor === 'co'} - /> -
-
-
-
- 아황산가스(So2) -
-
- handlerSensorClick('so2', e.target.checked)} - className='custom-control-primary' - type='switch' - id='sensorSo2' - name='sensorSo2' - inline - checked={mapControl.sensor === 'so2'} - // defaultChecked={mapControl.sensor === 'so2'} - /> -
-
-
-
-
-
*/}
); }; + export default ControlSetting;