sanguu516
6 months ago
10 changed files with 545 additions and 0 deletions
@ -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 ( |
||||
<div className='layer-content drone-list'> |
||||
{!results ? ( |
||||
<> |
||||
<div className='no-dataTable'>{EMPTY_MESSAGE}</div> |
||||
{loading && ( |
||||
<div |
||||
style={{ |
||||
display: 'flex', |
||||
justifyContent: 'center', |
||||
flexDirection: 'column', |
||||
alignItems: 'center' |
||||
}} |
||||
> |
||||
<Spinner color='primary' /> |
||||
<span>Loading...</span> |
||||
</div> |
||||
)} |
||||
</> |
||||
) : ( |
||||
<> |
||||
return ( |
||||
<div className='layer-ti'> |
||||
<h4>비행승인 신청 결과 목록 </h4> |
||||
<Badge color='light-primary' className='badge-glow'> |
||||
총 {results.length}건 결과 |
||||
</Badge> |
||||
</div> |
||||
{results.map(data => ( |
||||
<div |
||||
className={`layer-content-list ${ |
||||
data.cntrlId === props.selected ? 'on' : '' |
||||
}`}
|
||||
onClick={() => { |
||||
props.handlerDetail(data.cntrlId); |
||||
}} |
||||
key={Math.random()} |
||||
> |
||||
<dl> |
||||
<dt> |
||||
<div className='list-left-txt'>민원번호</div> |
||||
<div className='list-right-txt'>{data.complaint}</div> |
||||
</dt> |
||||
<dt> |
||||
<div className='list-left-txt'>위도/경도</div> |
||||
<div className='list-right-txt'>{data.coord}</div> |
||||
</dt> |
||||
<dt> |
||||
<div className='list-left-txt'>반경</div> |
||||
<div className='list-right-txt'>{data.radius}m</div> |
||||
</dt> |
||||
<dt> |
||||
<div className='list-left-txt'>고도</div> |
||||
<div className='list-right-txt'>{data.elev}m</div> |
||||
</dt> |
||||
<dt> |
||||
<div className='list-left-txt'>승인 결과</div> |
||||
<div className='list-right-txt'>{data.approval}</div> |
||||
</dt> |
||||
<dt> |
||||
<div className='list-left-txt'>사유</div> |
||||
<div className='list-right-txt'>{data.reason}</div> |
||||
</dt> |
||||
<dt> |
||||
<div className='list-left-txt'>담당 관할기관</div> |
||||
<div className='list-right-txt'>{data.Representative}</div> |
||||
</dt> |
||||
</dl> |
||||
</div> |
||||
))} |
||||
) |
||||
{false && ( |
||||
<div |
||||
style={{ |
||||
display: 'flex', |
||||
justifyContent: 'center', |
||||
flexDirection: 'column', |
||||
alignItems: 'center' |
||||
}} |
||||
> |
||||
<Spinner color='primary' /> |
||||
<span>Loading...</span> |
||||
</div> |
||||
)} |
||||
{/* <div ref={setTarget} /> */} |
||||
</> |
||||
)} |
||||
</div> |
||||
); |
||||
} |
@ -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 ( |
||||
<div className=''> |
||||
<div className='layer-content'> |
||||
<FlightApprovalsReport handlerSearch={handlerSearch} /> |
||||
<FlightApprovalsInfo |
||||
data={data} |
||||
filter={filter} |
||||
selected={selected} |
||||
handlerDetail={handlerDetail} |
||||
/> |
||||
</div> |
||||
</div> |
||||
); |
||||
} |
@ -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 ( |
||||
<div> |
||||
<div className='layer-ti'> |
||||
<h4>비행승인 신청 결과 현황</h4> |
||||
</div> |
||||
<div className='layer-search layer-search-form'> |
||||
<div></div> |
||||
<div> |
||||
<InputGroup> |
||||
<Input |
||||
type='text' |
||||
placeholder='관할기관을 입력해주세요.' |
||||
value={filterId} |
||||
onChange={e => setFilterId(`${e.target.value}`)} |
||||
/> |
||||
</InputGroup> |
||||
</div> |
||||
<div> |
||||
<Button |
||||
color='primary' |
||||
onClick={() => props.handlerSearch(filterId)} |
||||
size='sm' |
||||
> |
||||
검색 |
||||
</Button> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
); |
||||
} |
@ -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 ? ( |
||||
<div className='right-menu active'> |
||||
<button |
||||
className='right-layer-btn' |
||||
onClick={() => setOpenSetting(false)} |
||||
> |
||||
<Map size={18} /> |
||||
</button> |
||||
<div className='right-layer active' style={{ width: '500px' }}> |
||||
<FlightApprovalsList /> |
||||
</div> |
||||
</div> |
||||
) : ( |
||||
<div className='right-menu'> |
||||
<button |
||||
className='right-layer-btn' |
||||
onClick={() => setOpenSetting(true)} |
||||
> |
||||
<Map size={18} /> |
||||
</button> |
||||
<div className='right-layer'></div> |
||||
</div> |
||||
)} |
||||
<div className='main-data-box flight-data' style={{ width: '440px' }}> |
||||
<Card> |
||||
<div className='data-box-header'> |
||||
<span className='box-ti'>관활기관 신청 결과 건수</span> |
||||
</div> |
||||
<div |
||||
className='data-list-box' |
||||
style={{ |
||||
display: 'flex', |
||||
gap: '10px', |
||||
flexWrap: 'wrap' |
||||
}} |
||||
> |
||||
<div className='data-list'> |
||||
<span className=''>서울지방항공청 1건</span> |
||||
</div> |
||||
<div className='data-list'> |
||||
<span className=''>김포공항관리사무소 3건</span> |
||||
</div> |
||||
<div className='data-list'> |
||||
<span className=''>청주공항출장소 2건</span> |
||||
</div> |
||||
|
||||
<div |
||||
style={{ |
||||
display: 'flex', |
||||
gap: '10px', |
||||
justifyContent: 'start' |
||||
}} |
||||
> |
||||
<div className='data-list'> |
||||
<span className=''>부산지방공청 1건</span> |
||||
</div> |
||||
<div className='data-list'> |
||||
<span className=''>제주지방항공청 1건</span> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</Card> |
||||
</div> |
||||
</> |
||||
); |
||||
} |
@ -0,0 +1,7 @@
|
||||
export default [ |
||||
{ |
||||
id: 'flight_001', |
||||
title: '비행기관 신청 결과 건수', |
||||
navLink: '/flightApprovals' |
||||
} |
||||
]; |
@ -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; |
@ -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 ( |
||||
<div className='pal-container'> |
||||
{/* <Helmet> |
||||
<title>관제시스템</title> |
||||
</Helmet> */} |
||||
<div className='map' style={{ width: '100vw' }}> |
||||
<MapControl /> |
||||
</div> |
||||
<FlightApprovalsContainer />; |
||||
</div> |
||||
); |
||||
} |
Loading…
Reference in new issue