diff --git a/src/@core/layouts/components/menu/vertical-menu/index.js b/src/@core/layouts/components/menu/vertical-menu/index.js index a2463a26..c455b4af 100644 --- a/src/@core/layouts/components/menu/vertical-menu/index.js +++ b/src/@core/layouts/components/menu/vertical-menu/index.js @@ -11,6 +11,7 @@ import analysis from '@src/navigation/analysis'; import laanc from '@src/navigation/laanc'; import cstmrService from '@src/navigation/cstmrService'; import statistics from '@src/navigation/statistics'; +import flightApprovals from '@src/navigation/flight'; // ** Third Party Components import classnames from 'classnames'; @@ -48,6 +49,8 @@ const Sidebar = props => { return statistics; case 'cstmrService': return cstmrService; + case 'flightApprovals': + return flightApprovals; case '/': return []; } diff --git a/src/@core/layouts/components/navbar/NavbarUser.js b/src/@core/layouts/components/navbar/NavbarUser.js index ab28bf27..6b1bcc39 100644 --- a/src/@core/layouts/components/navbar/NavbarUser.js +++ b/src/@core/layouts/components/navbar/NavbarUser.js @@ -93,6 +93,17 @@ const NavbarUser = props => { LAANC 승인 관리 + + window.open('/flightApprovals', '_blank')} + // active={active === '2'} + // onClick={() => { + // toggle('2') + // }} + > + 비행승인 신청 결과 + + window.open('/control', '_blank')} diff --git a/src/components/flight/FlightApprovalsInfo.js b/src/components/flight/FlightApprovalsInfo.js new file mode 100644 index 00000000..a16e4bda --- /dev/null +++ b/src/components/flight/FlightApprovalsInfo.js @@ -0,0 +1,113 @@ +import dayjs from 'dayjs'; +import { useEffect, useState, useRef, useCallback } from 'react'; +import { useSelector } from '@src/redux/store'; +import { Spinner, Badge } from '@component/ui'; +import { EMPTY_MESSAGE } from '@src/configs/msgConst'; + +export default function FlightApprovalsInfo(props) { + const [results, setSearchResults] = useState([]); + + useEffect(() => { + if (props.data) { + setSearchResults(props.data); + } + }, []); + useEffect(() => { + if (props.filter) { + const results = props.data.filter(item => + item.Representative.toLowerCase().includes(props.filter.toLowerCase()) + ); + setSearchResults(results); + } + }, [props.filter]); + + return ( +
+ {!results ? ( + <> +
{EMPTY_MESSAGE}
+ {loading && ( +
+ + Loading... +
+ )} + + ) : ( + <> + return ( +
+

비행승인 신청 결과 목록

+ + 총 {results.length}건 결과 + +
+ {results.map(data => ( +
{ + props.handlerDetail(data.cntrlId); + }} + key={Math.random()} + > +
+
+
민원번호
+
{data.complaint}
+
+
+
위도/경도
+
{data.coord}
+
+
+
반경
+
{data.radius}m
+
+
+
고도
+
{data.elev}m
+
+
+
승인 결과
+
{data.approval}
+
+
+
사유
+
{data.reason}
+
+
+
담당 관할기관
+
{data.Representative}
+
+
+
+ ))} + ) + {false && ( +
+ + Loading... +
+ )} + {/*
*/} + + )} +
+ ); +} diff --git a/src/components/flight/FlightApprovalsList.js b/src/components/flight/FlightApprovalsList.js new file mode 100644 index 00000000..4ce08163 --- /dev/null +++ b/src/components/flight/FlightApprovalsList.js @@ -0,0 +1,253 @@ +import { + useEffect, + useState, + lazy, + useRef, + useCallback, + Suspense +} from 'react'; +import FlightApprovalsInfo from './FlightApprovalsInfo.js'; +import FlightApprovalsReport from './FlightApprovalsReport.js'; +import mapboxgl from 'mapbox-gl'; +import { MAPBOX_TOKEN } from '../../configs/constants'; +const FeatureAirZone = lazy(() => + import('../map/mapbox/feature/FeatureAirZone.js') +); +import MapboxDraw from '@mapbox/mapbox-gl-draw'; +import { + CircleMode, + DragCircleMode, + DirectMode, + SimpleSelectMode +} from 'mapbox-gl-draw-circle'; +import MapboxLanguage from '@mapbox/mapbox-gl-language'; +import threebox from 'threebox-plugin'; + +export default function FlightApprovalsList() { + const [data, setData] = useState([ + { + cntrlId: '580d97c7-a7f8-4378-90bc-6dbc42d85bd4', + complaint: '15000', + radius: '100', + coord: '37.33395/126.59298', + elev: '100', + approval: '승인', + reason: '관제권 내 허용 고도(50m/80m)', + Representative: '김포항공관리사무소', + stArea: ' 인천광역시 부평구 청천동 372', + cntrlStDt: '2023-11-22 13:14:12', + cntrlEndDt: '2023-11-22 13:16:29' + }, + { + cntrlId: '580d97c7-a7f8-4378-90bc-6dbc42d85bd5', + complaint: '15000', + radius: '100', + coord: '37.33395/126.59298', + elev: '100', + approval: '승인', + reason: '관제권 내 허용 고도(50m/80m)', + Representative: '김포항공관리사무소', + stArea: ' 인천광역시 부평구 청천동 372', + cntrlStDt: '2023-11-22 13:14:12', + cntrlEndDt: '2023-11-22 13:16:29' + }, + { + cntrlId: '580d97c7-a7f8-4378-90bc-6dbc42d85bd6', + complaint: '15000', + radius: '100', + elev: '100', + coord: '37.33395/126.59298', + approval: '승인', + reason: '관제권 내 허용 고도(50m/80m)', + Representative: '김포항공관리사무소', + stArea: ' 인천광역시 부평구 청천동 372', + cntrlStDt: '2023-11-22 13:14:12', + cntrlEndDt: '2023-11-22 13:16:29' + }, + { + cntrlId: '580d97c7-a7f8-4378-90bc-6dbc42d85bd7', + complaint: '15000', + radius: '100', + coord: '37.33395/126.59298', + elev: '100', + approval: '승인', + reason: '관제권 내 허용 고도(50m/80m)', + Representative: '김포항공관리사무소', + stArea: ' 인천광역시 부평구 청천동 372', + cntrlStDt: '2023-11-22 13:14:12', + cntrlEndDt: '2023-11-22 13:16:29' + }, + { + cntrlId: '580d97c7-a7f8-4378-90bc-6dbc42d85bd8', + complaint: '15000', + radius: '100', + coord: '37.33395/126.59298', + elev: '100', + approval: '승인', + reason: '관제권 내 허용 고도(50m/80m)', + Representative: '김포항공관리사무소', + stArea: ' 인천광역시 부평구 청천동 372', + cntrlStDt: '2023-11-22 13:14:12', + cntrlEndDt: '2023-11-22 13:16:29' + } + ]); + const [selected, setSelected] = useState(null); + const [isMapLoading, setIsMapLoading] = useState(false); + // 비행구역 그리기 + const [drawObj, setDrawObj] = useState(); + + const [filter, setFilter] = useState(''); + // 지도 + const [mapObject, setMapObject] = useState(); + const handlerSearch = search => { + setFilter(search); + + // setParams({ ...params, search1 }); + // dispatch( + // getSmltList({ + // searchParams: { ...params, search1 }, + // page: 1 + // }) + // ); + }; + + // 상세보기 + const handlerDetail = id => { + setSelected(id); + }; + + useEffect(() => { + // handlerMapInit(); + }, []); + + const handlerMapInit = () => { + mapboxgl.accessToken = MAPBOX_TOKEN; + const map = new mapboxgl.Map({ + container: 'map', + style: 'mapbox://styles/mapbox/streets-v12' + }); + + // 비행구역 상세맵 draw 정보 셋팅 + const draw = new MapboxDraw({ + displayControlsDefault: false, + userProperties: true, + boxSelect: false, + modes: { + ...MapboxDraw.modes, + draw_circle: CircleMode, + drag_circle: DragCircleMode, + direct_select: DirectMode, + simple_select: SimpleSelectMode + }, + styles: [ + { + // polyline + id: 'gl-draw-line', + type: 'line', + filter: [ + 'all', + ['==', '$type', 'LineString'], + ['!=', 'mode', 'static'] + ], + layout: { + 'line-cap': 'round', + 'line-join': 'round' + }, + paint: { + 'line-color': '#8a1c05', + 'line-dasharray': [0.2, 2], + 'line-width': 2 + } + }, + { + // polygon fill + id: 'gl-draw-polygon-fill', + type: 'fill', + filter: ['all', ['==', '$type', 'Polygon'], ['!=', 'mode', 'static']], + paint: { + 'fill-color': '#8a1c05', + 'fill-outline-color': '#8a1c05', + 'fill-opacity': 0.1 + } + }, + // polygon outline + { + id: 'gl-draw-polygon-stroke-active', + type: 'line', + filter: ['all', ['==', '$type', 'Polygon'], ['!=', 'mode', 'static']], + layout: { + 'line-cap': 'round', + 'line-join': 'round' + }, + paint: { + 'line-color': '#8a1c05', + 'line-dasharray': [0.2, 2], + 'line-width': 2 + } + }, + { + // vertex point halos + id: 'gl-draw-polygon-and-line-vertex-halo-active', + type: 'circle', + filter: [ + 'all', + ['==', 'meta', 'vertex'], + ['==', '$type', 'Point'], + ['!=', 'mode', 'static'] + ], + paint: { + 'circle-radius': 8, + 'circle-color': '#ffffff' + } + }, + { + // vertex points + id: 'gl-draw-polygon-and-line-vertex-active', + type: 'circle', + filter: [ + 'all', + ['==', 'meta', 'vertex'], + ['==', '$type', 'Point'], + ['!=', 'mode', 'static'] + ], + paint: { + 'circle-radius': 6, + 'circle-color': '#8a1c05' + } + } + ] + }); + + setDrawObj(draw); + map.dragRotate.disable(); + + const language = new MapboxLanguage(); + map.addControl(language); + + const tb = (window.tb = new threebox.Threebox( + map, + map.getCanvas().getContext('webgl'), + { + enableSelectingObjects: true, + enableTooltips: true + } + )); + + setMapObject(map); + // dispatch(clientMapInit(map)); + }; + + return ( +
+
+ + +
+
+ ); +} diff --git a/src/components/flight/FlightApprovalsReport.js b/src/components/flight/FlightApprovalsReport.js new file mode 100644 index 00000000..313362d5 --- /dev/null +++ b/src/components/flight/FlightApprovalsReport.js @@ -0,0 +1,39 @@ +import { useState } from 'react'; +import { Calendar, X } from 'react-feather'; +import Flatpickr from 'react-flatpickr'; +import { Button, Input, InputGroup } from '@component/ui'; + +export default function FlightApprovalsReport(props) { + // 식별번호 + const [filterId, setFilterId] = useState(''); + + return ( +
+
+

비행승인 신청 결과 현황

+
+
+
+
+ + setFilterId(`${e.target.value}`)} + /> + +
+
+ +
+
+
+ ); +} diff --git a/src/containers/flight/flightApprovalsContainer.js b/src/containers/flight/flightApprovalsContainer.js new file mode 100644 index 00000000..e3d45b31 --- /dev/null +++ b/src/containers/flight/flightApprovalsContainer.js @@ -0,0 +1,76 @@ +import { useEffect, useState, lazy, Suspense } from 'react'; +import { Card } from '@component/ui'; +import { Map } from 'react-feather'; +import FlightApprovalsList from '../../components/flight/FlightApprovalsList'; +export default function FlightApprovalsContainer() { + // 오른쪽 사이드 메뉴 표출 여부 + const [openSetting, setOpenSetting] = useState(true); + + return ( + <> + {openSetting ? ( +
+ +
+ +
+
+ ) : ( +
+ +
+
+ )} +
+ +
+ 관활기관 신청 결과 건수 +
+
+
+ 서울지방항공청 1건 +
+
+ 김포공항관리사무소 3건 +
+
+ 청주공항출장소 2건 +
+ +
+
+ 부산지방공청 1건 +
+
+ 제주지방항공청 1건 +
+
+
+
+
+ + ); +} diff --git a/src/navigation/flight/index.js b/src/navigation/flight/index.js new file mode 100644 index 00000000..848e2ecc --- /dev/null +++ b/src/navigation/flight/index.js @@ -0,0 +1,7 @@ +export default [ + { + id: 'flight_001', + title: '비행기관 신청 결과 건수', + navLink: '/flightApprovals' + } +]; diff --git a/src/router/routes/RouteFlight.js b/src/router/routes/RouteFlight.js new file mode 100644 index 00000000..ac495aa6 --- /dev/null +++ b/src/router/routes/RouteFlight.js @@ -0,0 +1,13 @@ +import { lazy } from 'react'; + +const RouteFlight = [ + { + path: '/analysis/history/list', + component: lazy(() => import('../../views/flight/FlightView')), + meta: { + authRoute: true + } + } +]; + +export default RouteFlight; diff --git a/src/router/routes/index.js b/src/router/routes/index.js index 41205ed7..7ebcb4f1 100644 --- a/src/router/routes/index.js +++ b/src/router/routes/index.js @@ -7,6 +7,8 @@ import RouteWeather from './RouteWeather'; import RouteLaance from './RouteLaance'; import RouterCstmrService from './RouterCstmrService'; import RouteStatistics from './RouteStatistics'; +import RouteFlight from './RouteFlight'; + // ** Document title const TemplateTitle = '%s - Dron Control System'; @@ -23,6 +25,7 @@ const Routes = [ ...RouteLaance, ...RouterCstmrService, ...RouteStatistics, + ...RouteFlight, { path: '/home', component: lazy(() => import('../../views/Home')) @@ -86,6 +89,14 @@ const Routes = [ authRoute: true } }, + { + path: '/flightApprovals', + component: lazy(() => import('../../views/flight/FlightView')), + layout: 'BlankLayout', + meta: { + authRoute: true + } + }, { path: '/history/record/sample1', component: lazy(() => diff --git a/src/views/flight/FlightView.js b/src/views/flight/FlightView.js new file mode 100644 index 00000000..93b144e0 --- /dev/null +++ b/src/views/flight/FlightView.js @@ -0,0 +1,19 @@ +import '@styles/react/libs/flatpickr/flatpickr.scss'; +import '@styles/react/libs/tables/react-dataTable-component.scss'; +import '../../assets/css/custom.css'; +import FlightApprovalsContainer from '../../containers/flight/flightApprovalsContainer'; +import { MapControl } from '../../components/map/MapControl'; + +export default function FlightView() { + return ( +
+ {/* + 관제시스템 + */} +
+ +
+ ; +
+ ); +}