Browse Source

비행 계획서 개발

pull/1/head
노승철 2 years ago
parent
commit
e169cdb4d6
  1. 1
      src/assets/css/custom.css
  2. 112
      src/components/basis/flight/plan/FlightPlanArcrft.js
  3. 197
      src/components/basis/flight/plan/FlightPlanAreaDetailForm.js
  4. 115
      src/components/basis/flight/plan/FlightPlanAreaForm.js
  5. 165
      src/components/basis/flight/plan/FlightPlanAreaMap.js
  6. 49
      src/components/basis/flight/plan/FlightPlanAreaModal.js
  7. 1349
      src/components/basis/flight/plan/FlightPlanForm.js
  8. 128
      src/components/basis/flight/plan/FlightPlanGrid.js
  9. 67
      src/components/basis/flight/plan/FlightPlanGroupGrid.js
  10. 29
      src/components/basis/flight/plan/FlightPlanModal.js
  11. 107
      src/components/basis/flight/plan/FlightPlanPilot.js
  12. 329
      src/components/basis/flight/plan/FlightPlanSearch.js
  13. 652
      src/components/map/naver/draw/FlightPlanDraw.js
  14. 676
      src/components/map/naver/draw/FlightPlanDrawTest.js
  15. 2
      src/components/mapDraw/naver/draw/JQueryDraw.js
  16. 45
      src/containers/basis/flight/plan/FlightPlanArcrftContainer.js
  17. 83
      src/containers/basis/flight/plan/FlightPlanAreaContainer.js
  18. 86
      src/containers/basis/flight/plan/FlightPlanAreaDetailContainer.js
  19. 140
      src/containers/basis/flight/plan/FlightPlanContainer.js
  20. 407
      src/containers/basis/flight/plan/FlightPlanDetailContainer.js
  21. 44
      src/containers/basis/flight/plan/FlightPlanPilotContainer.js
  22. 210
      src/modules/basis/flight/actions/basisFlightAction.ts
  23. 62
      src/modules/basis/flight/apis/basisFlightApi.ts
  24. 472
      src/modules/basis/flight/models/basisFlightModel.ts
  25. 114
      src/modules/basis/flight/reducers/basisFlightReducer.ts
  26. 337
      src/modules/basis/flight/sagas/basisFlightSaga.ts
  27. 4
      src/modules/control/map/reducers/controlMapReducer.ts
  28. 2
      src/router/routes/RouteBasis.js

1
src/assets/css/custom.css

@ -250,6 +250,7 @@ h1.logo span{display:block;color:#f4f4f4;font-weight:bold;letter-spacing:2px;fon
.left-menu-nav .test .btn-use{margin-left:20px; width: 35px; height: 35px; display: block; border: 0px solid transparent; box-sizing: content-box !important; background-color: #009cad;}
.measure-control{position:absolute; z-index:100;}
.area-button{position:relative; z-index:100; margin-top:10px; margin-left:10px;}
.control-btn{margin-left: 7px; border-bottom: solid 1px #283046; margin-bottom:5px;}
.buffer-input{text-align: center; border-radius: 100px; border: 1px solid #283046; width: 70px; margin-left: 5px;}

112
src/components/basis/flight/plan/FlightPlanArcrft.js

@ -0,0 +1,112 @@
import React from 'react';
import {Button, Card, CardBody, Col, CustomInput, Row, FormGroup, Input, Label} from 'reactstrap';
import {Search} from 'react-feather';
import {GridDatabase} from '../../../crud/grid/GridDatatable';
const FlightPlanArcrft = ({ arcrftList, handleSelectArcrft }) => {
const columns = [
{id: 'groupNm', name: '그룹 명', cell: row => (<div>{row.groupNm}</div>)},
{id: 'arcrftModelNm', name: '모델 명', cell: row => (<div>{row.arcrftModelNm}</div>)},
{id: 'idntfTypeCd', name: '종류', cell: row => (<div>{row.arcrftTypeCd}</div>)},
{id: 'ownerNm', name: '소유자 명', cell: row => (<div>{row.ownerNm}</div>)},
{id: 'idntfNum', name: '식별 코드', cell: row => (<div>{row.idntfNum}</div>)},
{
id: 'selectPilot', name: '선택', cell: row => {
return <Button.Ripple color='primary' size='sm' onClick={() => {
handleSelectArcrft(row.arcrftSno)
}
}>선택</Button.Ripple>;
}
}
];
return (
<>
<div className='pal-card-box'>
<Row>
<Col>
<div
className='cont-ti d-flex justify-content-between align-items-sm-center align-items-start flex-sm-row'>
<div>
<h4>검색조건</h4>
</div>
<div className='d-flex align-items-center'>
<Button.Ripple
color='primary'
size='sm'
// onClick={handleClickSearch}
>
<Search size={16}/>
검색
</Button.Ripple>
</div>
</div>
<Card>
<CardBody className='pal-card-body'>
<div className='search-cont'>
<dl>
<dt>
<div className='search-box'>
<div className='search-list-ti'>소유자 </div>
<div className='search-list'>
<div className='search-list-cont'>
<Row>
<Col className='list-input' xl='4' md='4' sm='12'>
<FormGroup className='form-label-group'>
<Input
type='text'
id='ownerNm'
name='ownerNm'
// value={props.params.groupNm}
// onChange={props.handlerInput}
bsSize='sm'
// onKeyPress={props.onKeyPress}
placeholder='소유자 명을 입력하세요'
/>
<Label for='test'>소유자 </Label>
</FormGroup>
</Col>
</Row>
</div>
</div>
</div>
</dt>
</dl>
</div>
</CardBody>
</Card>
</Col>
</Row>
</div>
<div className='pal-card-box'>
<Row>
<Col>
<div className='cont-ti d-flex justify-content-between align-items-sm-center align-items-start flex-sm-row'>
<div>
<h4>기체 목록</h4>
<span className='search-case'>검색결과 {!!arcrftList ? arcrftList.length : 0}</span>
</div>
</div>
<div className='invoice-list-wrapper'>
<Card>
<div className='invoice-list-dataTable'>
<GridDatabase
data={arcrftList}
count={arcrftList ? arcrftList.length : 0}
columns={columns}
// pagination={props.pagination}
/>
{/* 검색된 데이터가 없습니다. */}
</div>
</Card>
</div>
</Col>
</Row>
</div>
</>
)
}
export default FlightPlanArcrft;

197
src/components/basis/flight/plan/FlightPlanAreaDetailForm.js

@ -0,0 +1,197 @@
import React, { useEffect, useState } from 'react';
import {
Card,
CardBody,
Col,
FormGroup,
Input,
Label,
Row,
Button
} from 'reactstrap';
const FlightPlanAreaDetailForm = ({ handleSave, handleClose, handleChange, handleBufferList, data }) => {
const coordList = data ? data[0].coordList : null;
return (
<Card className='mb-0'>
<CardBody>
<Row>
<Col>
<Card>
<CardBody className='pal-card-body'>
<div className='search-cont search-info pd-0'>
<div className='cont-ti mb-1 d-flex justify-content-between align-items-sm-center align-items-start flex-sm-row'>
<div>
<h4>비행 구역 상세 정보</h4>
</div>
</div>
<dl>
<dt>
<div className='search-info-ti d-flex justify-content-between'>
<h4 className='ti'>좌표 정보</h4>
</div>
<div className='search-info-box'>
<Row>
{coordList ?
coordList.map((coord, idx) => {
const latlon = coord.lat + ' / ' + coord.lon;
return (
<Col key={idx} className='list-input' lg={6} md={6} sm={12}>
<FormGroup>
<Label for='test'><span className='necessary'>*</span> {idx+1} </Label>
<Input
type='text'
name='coord'
bsSize='sm'
placeholdeer=''
readOnly
value={latlon}
/>
</FormGroup>
</Col>
)
})
:
<Col className='list-input' lg={6} md={6} sm={12}>
<FormGroup>
<Label for='test'><span className='necessary'>*</span> 1</Label>
<Input
type='text'
name='coord'
bsSize='sm'
placeholdeer=''
readOnly
/>
</FormGroup>
</Col>
}
</Row>
</div>
</dt>
<dt>
<div className='search-info-ti d-flex justify-content-between'>
<h4 className='ti'>기타 정보</h4>
</div>
<div className='search-info-box'>
<Row>
<Col className='list-input' lg={6} md={6} sm={12}>
<FormGroup className='m_ft'>
<div className='m_ft_box'>
<Label for='test'><span className='necessary'>*</span>(m)</Label>
<Input
type='text'
id='bufferZone'
name='bufferZone'
bsSize='sm'
placeholder='반경'
value={data ? data[0].bufferZone : ''}
onChange={(e) => {
const {name, value} = e.target;
handleChange({
name,
value
})
}}
/>
</div>
<div className='m_ft_box'>
<Button.Ripple
className='mr-1'
color='primary'
size='sm'
onClick={() => handleBufferList()}
>
적용
</Button.Ripple>
</div>
</FormGroup>
</Col>
</Row>
</div>
<div className='search-info-box'>
<Row>
<Col className='list-input' lg={6} md={6} sm={12}>
<FormGroup>
<Label for='test'><span className='necessary'>*</span>(ft)</Label>
<Input
type='text'
id='fltElev'
name='fltElev'
bsSize='sm'
placeholder='고도'
value={data ? data[0].fltElev : ''}
onChange={(e) => {
const {name, value} = e.target;
handleChange({
name,
value
})
}}
/>
</FormGroup>
</Col>
</Row>
</div>
<div className='search-info-box'>
<Row>
<Col className='list-input' lg={6} md={6} sm={12}>
<FormGroup>
<Label for='test'><span className='necessary'>*</span> </Label>
<Input
type='text'
id='fltMethod'
name='fltMethod'
bsSize='sm'
placeholder='비행 방식'
value={data ? data[0].fltMethod : ''}
onChange={(e) => {
const {name, value} = e.target;
handleChange({
name,
value
})
}}
/>
</FormGroup>
</Col>
</Row>
</div>
</dt>
</dl>
</div>
<div className='d-flex align-items-center mt-2'>
<Button.Ripple
type='submit'
className='mr-1'
color='primary'
onClick={e => handleSave()}
>
등록
</Button.Ripple>
<Button.Ripple
className='mr-1'
color='primary'
onClick={e => handleClose()}
>
닫기
</Button.Ripple>
</div>
</CardBody>
</Card>
</Col>
</Row>
</CardBody>
</Card>
)
}
export default FlightPlanAreaDetailForm;

115
src/components/basis/flight/plan/FlightPlanAreaForm.js

@ -1,115 +0,0 @@
import React, { useState, useEffect } from 'react';
import classnames from 'classnames';
import {
Card,
CardBody,
Col,
FormGroup,
FormFeedback,
Input,
Label,
Row,
Button,
Form
} from 'reactstrap';
const FlightPlanAreaForm = (props) => {
return (
<Card>
<CardBody>
<div className='search-cont search-info pd-0'>
<div className='cont-ti mb-1 d-flex justify-content-between align-items-sm-center align-items-start flex-sm-row'>
<div>
<h4>상세 정보</h4>
</div>
<div className='final'>
{/* {props.type === 'update' ? (
<span>최종 수정일자 : {props.updateDt}</span>
) : null} */}
</div>
</div>
<dl>
<dt>
<div className='search-info-box'>
<Row>
<Col className='list-input' lg={6} md={6} sm={12}>
<FormGroup>
<Label for='test'>
<span className='necessary'></span>(m)
</Label>
<Input
type='text'
id='radius'
name='radius'
size='sm'
placeholder=''
innerRef={props.data}
/>
</FormGroup>
</Col>
</Row>
</div>
<div className='search-info-box'>
<Row>
<Col className='list-input' lg={6} md={6} sm={12}>
<FormGroup className='m_ft'>
<div className='m_ft_box'>
<Label for='test'>
<span className='necessary'></span>(m/ft)
</Label>
<Input
type='text'
id='altitude_m'
name='altitude_m'
size='sm'
placeholder='m'
innerRef={props.data}
/>
</div>
<div className='m_ft_box'>
<Input
type='text'
id='altitude'
name='altitude'
size='sm'
placeholder='ft'
innerRef={props.data}
/>
</div>
</FormGroup>
</Col>
</Row>
</div>
<Button.Ripple
className='mr-1'
color='primary'
size='sm'
onClick={
props.submit
}
>
확인
</Button.Ripple>
<Button.Ripple
className='mr-1'
color='danger'
size='sm'
onClick={() =>
props.setModal({ ...props.modal, isOpen: !props.modal.isOpen })
}
>
취소
</Button.Ripple>
</dt>
</dl>
</div>
</CardBody>
</Card>
)
}
export default FlightPlanAreaForm;

165
src/components/basis/flight/plan/FlightPlanAreaMap.js

@ -2,74 +2,183 @@ import React, { useEffect, useState } from 'react';
import {
Card,
CardBody,
Button
Button,
Row,
Label,
Input,
Col,
FormGroup
} from 'reactstrap';
import { useDispatch, useSelector } from 'react-redux';
import * as Actions from '../../../../modules/basis/flight/actions/basisFlightAction';
import { FeatureAirZone } from '../../../map/naver/feature/FeatureAirZone';
import { drawTypeChangeAction, drawCheckAction } from '../../../../modules/control/map/actions/controlMapActions';
import { FlightPlanDrawTest } from '../../../map/naver/draw/FlightPlanDrawTest';
import { initFlight, initFlightBas } from '../../../../modules/basis/flight/models/basisFlightModel';
import { AREA_COORDINATE_LIST_SAVE } from '../../../../modules/basis/flight/actions/basisFlightAction';
const FlightPlanAreaMap = (props) => {
const dispatch = useDispatch();
const naver = window.naver;
const airArea = props.airArea;
const airArea = props.airArea;
const mapControl = useSelector(state => state.controlMapReducer);
const { areaCoordList } = useSelector(state => state.flightState);
const [map, setMap] = useState();
const [isMapLoad, setIsMapLoad] = useState(false);
const [mode, setMode] = useState();
const [mapAreaCoordList, setMapAreaCoordList] = useState(initFlightBas.initDetail.areaList);
useEffect(() => {
NaverMapInit();
useEffect(() => {
NaverMapInit();
}, []);
useEffect(() => {
useEffect(() => {
setIsMapLoad(true);
}, [airArea]);
useEffect(() => {
ModeInit();
}, [mapControl.drawType]);
useEffect(() => {
setMapAreaCoordList(areaCoordList)
}, [areaCoordList]);
const [areaDetail, setAreaDetail] = useState(initFlightBas.initDetail.areaList);
const ModeInit = () => {
setMode(mapControl.drawType)
}
const NaverMapInit = () => {
const mapOptions = {
center: new naver.maps.LatLng(36.56793936069445, 127.85101412107547),
zoom: 10,
// center: new naver.maps.LatLng(36.56793936069445, 127.85101412107547),
center: new naver.maps.LatLng(37.520357, 126.610166),
// zoom: 10,
zoom: 15,
zoomControl: true,
mapTypeId: naver.maps.MapTypeId.HYBRID,
mapTypeId: naver.maps.MapTypeId.NORMAL,
zoomControlOptions: {
position: naver.maps.Position.TOP_LEFT,
style: naver.maps.ZoomControlStyle.SMALL
position: naver.maps.Position.LEFT_CENTER,
style: naver.maps.ZoomControlStyle.SMALL
}
};
setMap(new naver.maps.Map('map', mapOptions));
};
setMap(new naver.maps.Map('map', mapOptions));
};
const handlerDrawType = val => {
dispatch(drawTypeChangeAction(val));
};
const handleBufferList = () => {
dispatch(Actions.FLIGHT_PLAN_AREA_BUFFER_LIST.request(areaDetail));
}
const handleInitCoordinates = () => {
const init = initFlightBas.initDetail.areaList.concat();
dispatch(AREA_COORDINATE_LIST_SAVE(init))
}
const handleCoordinates = (areaInfo) => {
const initAreaList = initFlightBas.initDetail.areaList.concat()
const coordList = [];
// radius = 10;
areaInfo.coordinates.forEach((c, i) => {
const coord = Object.assign({}, initFlightBas['coord']);
coord.lat = c.lat;
coord.lon = c.lon;
coordList.push(coord);
});
// initAreaList[0].bufferZone = areaInfo.bufferZone;
// initAreaList[0].areaType = areaInfo.areaType;
const areaList = initAreaList.map((area, i) => {
return {
...area,
bufferZone: areaInfo.bufferZone,
areaType: areaInfo.areaType,
coordList : coordList
}
})
// dispatch(AREA_COORDINATE_LIST_SAVE(areaList))
setMapAreaCoordList(areaList);
}
return (
<Card className='mb-0'>
<CardBody>
<CardBody>
<div className='search-cont search-info pd-0'>
<div className='cont-ti mb-1 d-flex justify-content-between align-items-sm-center align-items-start flex-sm-row'>
<div>
<h4>지도 영역</h4>
</div>
</div>
</div>
</div>
<div style={{ position: 'relative' }}>
<div id="map" style={{ width: '100%', height: '60vh' }}>
{isMapLoad ? <FlightPlanDrawTest
map={map}
naver={naver}
mode={mode}
areaCoordList={mapAreaCoordList}
handleCoordinates={handleCoordinates}
handleInitCoordinates={handleInitCoordinates}
handleBufferList={handleBufferList}
/> : null}
<Button.Ripple
color='primary'
className='area-button'
onClick = {e => props.handleConfirm(mapAreaCoordList)}
>
확인
</Button.Ripple>
<Button.Ripple
color='primary'
className='area-button'
onClick={e => handlerDrawType('RESET')}
>
초기화
</Button.Ripple>
</div>
</div>
<div id="map" style={{ width: '100%', height: '50vh'}}></div>
{isMapLoad ? (
<FeatureAirZone map={map} naver={naver} features={airArea.features} />
{isMapLoad ? (
<FeatureAirZone map={map} naver={naver} features={airArea.features} />
) : null}
<div className='d-flex align-items-center mt-2'>
<Button.Ripple
className='mr-1'
color='primary'
color='primary'
onClick={e => handlerDrawType('LINE')}
>
Line
WayPoint
</Button.Ripple>
<Button.Ripple
color='primary'
<Button.Ripple
className='mr-1'
color='primary'
onClick={e => handlerDrawType('CIRCLE')}
>
Circle
</Button.Ripple>
</div>
<Button.Ripple
color='primary'
onClick={e => handlerDrawType('POLYGON')}
>
Polygon
</Button.Ripple>
</div>
</CardBody>
</Card>
)

49
src/components/basis/flight/plan/FlightPlanAreaModal.js

@ -1,49 +0,0 @@
import { useState } from 'react';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
import FlightPlanAreaContainer from '../../../../containers/basis/flight/plan/FlightPlanAreaContainer';
export const FlightPlanAreaModal = props => {
const [onSubmit, setOnSubmit] = useState(false);
return (
<div className='vertically-centered-modal'>
<Modal
isOpen={props.modal.isOpen}
toggle={() =>
props.setModal({ ...props.modal, isOpen: !props.modal.isOpen })
}
className='modal-dialog-centered modal-xl'
>
<ModalHeader
toggle={() =>
props.setModal({ ...props.modal, isOpen: !props.modal.isOpen })
}
>
{props.modal.title}
</ModalHeader>
<ModalBody>
<FlightPlanAreaContainer
modal={props.modal}
setModal={props.setModal}
onSubmit={onSubmit}
setOnSubmit={setOnSubmit}
/>
</ModalBody>
{/* <ModalFooter>
<Button
type="submit"
color='primary'
// onClick={() =>
// // props.setModal({ ...props.modal, isOpen: !props.modal.isOpen })
// setOnSubmit(true)
// }
outline
>
저장
</Button>
</ModalFooter> */}
</Modal>
</div>
);
};

1349
src/components/basis/flight/plan/FlightPlanForm.js

File diff suppressed because it is too large Load Diff

128
src/components/basis/flight/plan/FlightPlanGrid.js

@ -1,66 +1,70 @@
import React from 'react';
import {
Row,
Col,
Table,
Badge,
UncontrolledDropdown,
DropdownMenu,
DropdownItem,
DropdownToggle,
Card,
CardHeader,
CardBody,
CardTitle,
CardSubtitle,
ButtonGroup,
Button,
Input,
CustomInput,
FormGroup
} from 'reactstrap';
import { GridDatabase } from '../../../crud/grid/GridDatatable';
import {Button, Card, Col, Row} from 'reactstrap';
import {GridDatabase} from '../../../crud/grid/GridDatatable';
import {Redirect} from 'react-router-dom';
const FlightPlanGrid = (props) => {
return (
<div className='pal-card-box'>
<Row>
<Col>
<div className='cont-ti d-flex justify-content-between align-items-sm-center align-items-start flex-sm-row'>
<div>
{/* <h4>{"비행 계획"} 목록</h4> */}
<h4>{"비행계획서 신청"} 목록</h4>
<span className='search-case'>검색결과 0</span>
</div>
<div className='d-flex align-items-center'>
<Button.Ripple
color='primary'
size='sm'
onClick={props.moveFlightPlan}
>
{/* 계획서 생성 */}
비행계획서 신청
</Button.Ripple>
</div>
</div>
<div className='invoice-list-wrapper'>
<Card>
<div className='invoice-list-dataTable'>
<GridDatabase
title={'비행이력'}
// data={props.data}
count={0}
// columns={props.columns}
// pagination={props.pagination}
/>
{/* 검색된 데이터가 없습니다. */}
</div>
</Card>
</div>
</Col>
</Row>
</div>
)
const FlightPlanGrid = ({movePage, planListData, handleMoveDetail}) => {
const columns = [
{id: 'planSno', name: '번호', cell: (row, i) => (<div>{i+1}</div>)},
{id: 'fltPurpose', name: '비행목적', cell: row => (<div>{row.fltPurpose}</div>)},
{
id: 'fltMethod', name: '비행방식', cell: row => {
const displayName = row.areaList && row.areaList.length > 0 && row.areaList[0].fltMethod || '-';
return <div>{displayName}</div>
}
},
{id: 'schFltStDt', name: '출발일', cell: row => (<div>{row.schFltStDt}</div>)},
{id: 'aprvlYn', name: '승인여부', cell: row => (<div>{row.aprvlYn}</div>)},
{
id: 'moveDetail', name: '상세보기', cell: row => {
return <Button.Ripple color='primary' size='sm' onClick={() => {
handleMoveDetail(row.planSno)}
}>상세</Button.Ripple>;
}
}
];
return (
<div className='pal-card-box'>
<Row>
<Col>
<div
className='cont-ti d-flex justify-content-between align-items-sm-center align-items-start flex-sm-row'>
<div>
<h4>비행계획서 신청 목록</h4>
<span className='search-case'>검색결과 {!!planListData ? planListData.length : 0}</span>
</div>
<div className='d-flex align-items-center'>
<Button.Ripple
color='primary'
size='sm'
onClick={movePage}
>
{/* 계획서 생성 */}
비행계획서 신청
</Button.Ripple>
</div>
</div>
<div className='invoice-list-wrapper'>
<Card>
<div className='invoice-list-dataTable'>
<GridDatabase
title={'비행이력'}
data={planListData}
columns={columns}
count={!!planListData ? planListData.length : 0}
// pagination={props.pagination}
/>
{/* 검색된 데이터가 없습니다. */}
</div>
</Card>
</div>
</Col>
</Row>
</div>
)
}
export default FlightPlanGrid;
export default FlightPlanGrid;

67
src/components/basis/flight/plan/FlightPlanGroupGrid.js

@ -0,0 +1,67 @@
import React, {} from 'react';
import { GridDatabase } from "../../../crud/grid/GridDatatable";
import {
Card,
Button
} from 'reactstrap';
const FlightPlanGroupGrid = ({ data, count, selectGroup, handlerGroupCancel, handleGroupSelect }) => {
const columns = [
{id: 'groupNm', name: '그룹 명', minWidth: '102px', cell: row => (<div>{row.groupNm}</div>)},
{id: 'groupId', name: '그룹 코드', minWidth: '102px', sortable: true, cell: row => (<div>{row.groupId}</div>)},
{sortable: true, cell: row => {
return selectGroup?.groupId === row?.groupId ? (
<Button.Ripple
color='danger'
className='badge badge-danger'
onClick={() => handlerGroupCancel()}
>
선택취소
</Button.Ripple>
) : (
<Button.Ripple
color='primary'
className='badge badge-primary'
onClick={() => {
handleGroupSelect({
groupId: row?.groupId,
groupNm: row?.groupNm,
groupAuthCd: row?.groupAuthCd
})
}
}
>
상세보기
</Button.Ripple>
)
}}
];
return (
<>
<div className='cont-ti d-flex justify-content-between align-items-sm-center align-items-start flex-sm-row'>
<div>
<h4>나의 그룹 목록</h4>
<span className='search-case'>검색결과 {count}</span>
</div>
<div className='d-flex align-items-center'></div>
</div>
<div className='invoice-list-wrapper'>
<Card>
<div className='invoice-list-dataTable'>
<GridDatabase
data={data}
count={count}
columns={columns}
/>
</div>
</Card>
</div>
</>
)
}
export default FlightPlanGroupGrid;

29
src/components/basis/flight/plan/FlightPlanModal.js

@ -0,0 +1,29 @@
import { useState } from 'react';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
import FlightPlanAreaContainer from '../../../../containers/basis/flight/plan/FlightPlanAreaContainer';
export const FlightPlanModal = ({isOpen, title, description, type, handleModal}) => {
return (
<div className='vertically-centered-modal'>
<Modal
isOpen={isOpen}
toggle={() =>
handleModal(({target: type, isOpen: false}))
}
className='modal-dialog-centered modal-xl'
>
<ModalHeader
toggle={() =>
handleModal(({target: type, isOpen: false}))
}
>
{title}
</ModalHeader>
<ModalBody>
{description}
</ModalBody>
</Modal>
</div>
);
};

107
src/components/basis/flight/plan/FlightPlanPilot.js

@ -0,0 +1,107 @@
import React from 'react';
import {Button, Card, CardBody, Col, CustomInput, Row, FormGroup, Input, Label} from 'reactstrap';
import {Search} from 'react-feather';
import {GridDatabase} from '../../../crud/grid/GridDatatable';
const FlightPlanPilot = ({ pilotList, handleSelectPilot }) => {
const columns = [
{id: 'groupNm', name: '그룹 명', cell: row => (<div>{row.groupNm}</div>)},
{id: 'memberName', name: '성명', cell: row => (<div>{row.memberName}</div>)},
{id: 'hpno', name: '핸드폰 번호', cell: row => (<div>{row.hpno}</div>)},
{id: 'email', name: '이메일', cell: row => (<div>{row.email}</div>)},
{
id: 'selectPilot', name: '선택', cell: row => {
return <Button.Ripple color='primary' size='sm' onClick={() => {
handleSelectPilot(row.cstmrSno)
}
}>선택</Button.Ripple>;
}
}
];
return (
<>
<div className='pal-card-box'>
<Row>
<Col>
<div
className='cont-ti d-flex justify-content-between align-items-sm-center align-items-start flex-sm-row'>
<div>
<h4>검색조건</h4>
</div>
<div className='d-flex align-items-center'>
<Button.Ripple
color='primary'
size='sm'
// onClick={handleClickSearch}
>
<Search size={16}/>
검색
</Button.Ripple>
</div>
</div>
<Card>
<CardBody className='pal-card-body'>
<div className='search-cont'>
<dl>
<dt>
<div className='search-box'>
<div className='search-list-ti'>성명</div>
<div className='search-list'>
<div className='search-list-cont'>
<Row>
<Col className='list-input' xl='4' md='4' sm='12'>
<FormGroup className='form-label-group'>
<Input
type='text'
id='memberName'
name='memberName'
// value={props.params.groupNm}
// onChange={props.handlerInput}
bsSize='sm'
// onKeyPress={props.onKeyPress}
placeholder='성명을 입력하세요'
/>
<Label for='test'>성명</Label>
</FormGroup>
</Col>
</Row>
</div>
</div>
</div>
</dt>
</dl>
</div>
</CardBody>
</Card>
</Col>
</Row>
</div>
<div className='pal-card-box'>
<div className='cont-ti d-flex justify-content-between align-items-sm-center align-items-start flex-sm-row'>
<div>
<h4>조종사 목록</h4>
<span className='search-case'>검색결과 {!!pilotList ? pilotList.length : 0}</span>
</div>
<div className='d-flex align-items-center'></div>
</div>
<div className='invoice-list-wrapper'>
<Card>
<div className='invoice-list-dataTable'>
<GridDatabase
data={pilotList}
count={pilotList ? pilotList.length : 0}
columns={columns}
// pagination={props.pagination}
/>
</div>
</Card>
</div>
</div>
</>
)
}
export default FlightPlanPilot;

329
src/components/basis/flight/plan/FlightPlanSearch.js

@ -1,174 +1,175 @@
import React, { useEffect, useState } from 'react';
import {
Row,
Col,
Table,
Badge,
UncontrolledDropdown,
DropdownMenu,
DropdownItem,
DropdownToggle,
Card,
CardHeader,
CardBody,
CardTitle,
CardSubtitle,
ButtonGroup,
Button,
Input,
CustomInput,
FormGroup
} from 'reactstrap';
import { Calendar, Search } from 'react-feather';
import React, {useState} from 'react';
import {Button, Card, CardBody, Col, CustomInput, Row} from 'reactstrap';
import {Search} from 'react-feather';
import Flatpickr from 'react-flatpickr';
import moment from 'moment';
const FlightPlanSearch = (props) => {
const FlightPlanSearch = ({searchData, handleChangeSearchData, handleSearch}) => {
const [isCheck, setIsCheck] = useState({
all: true,
yes: false,
no: false
});
useEffect(() => {
let aprvYn = '';
if (!isCheck.all) {
if (isCheck.yes) {
aprvYn = 'Y';
} else if (isCheck.no) {
aprvYn = 'N';
} else {
aprvYn = '-';
}
const {schFltStDt, schFltEndDt, aprvlYn} = searchData;
const initCheckState = {
'all': aprvlYn == 'A',
'yes': (aprvlYn == 'Y' || aprvlYn == 'A'),
'no': (aprvlYn == 'N' || aprvlYn == 'A'),
}
// props.setParams({
// ...props.params,
// aprvYn: aprvYn
// });
}, [isCheck]);
return (
<div className='pal-card-box'>
<Row>
<Col>
<div className='cont-ti d-flex justify-content-between align-items-sm-center align-items-start flex-sm-row'>
<div>
<h4>검색조건</h4>
</div>
<div className='d-flex align-items-center'>
<Button.Ripple
color='primary'
size='sm'
onClick={e => props.handlerSearch()}
>
<Search size={16} />
검색
</Button.Ripple>
</div>
</div>
<Card>
<CardBody className='pal-card-body'>
<div className='search-cont'>
<dl>
<dt>
<div className='search-box'>
<div className='search-list-ti'>신청일</div>
<div className='search-list'>
<div className='search-list-cont'>
<Row>
<Col className='list-input' xl='4' md='6' sm='12'>
<div className='d-flex align-items-center calendar-flat'>
<Flatpickr
id='searchDate'
value={[
props.params.stDate,
props.params.endDate
]}
options={{
mode: 'range',
defaultDate: [
props.params.stDate,
props.params.endDate
]
}}
onChange={val =>
props.handlerInput('searchDate', val)
}
onKeyPress={props.onKeyPress}
className='form-control flat-picker bg-transparent border-0 shadow-none'
/>
</div>
</Col>
</Row>
const [checkState, setCheckState] = useState(initCheckState);
const handleClickSearch = (e) => {
handleSearch(searchData);
}
const handleChangeInput = (dates, value, config) => {
if (dates.length === 2) {
const schFltStDt = moment(dates[0]).format('YYYY-MM-DD HH:mm:ss');
const schFltEndDt = moment(dates[1]).set({'h': 23, 'm': 59, 's': 59}).format('YYYY-MM-DD HH:mm:ss');
handleChangeSearchData({schFltStDt, schFltEndDt})
}
}
const handleChangeCheckbox = (e) => {
const {name, value, checked} = e.target;
let val;
switch (value) {
case 'A':
val = checked ? 'A' : '';
handleChangeSearchData({[name]: val})
setCheckState({
'all': checked,
'yes': checked,
'no': checked
})
break;
case 'Y':
if (checked && checkState.no) val = 'A'
else if (checked && !checkState.no) val = 'Y'
else if (!checked && checkState.no) val = 'N'
else if (!checked && !checkState.no) val = ''
handleChangeSearchData({[name]: val})
setCheckState(prevState => ({
'all': prevState.no && checked,
'yes': checked,
'no': prevState.no
}))
break;
case 'N':
if (checked && checkState.yes) val = 'A'
else if (checked && !checkState.yes) val = 'N'
else if (!checked && checkState.yes) val = 'Y'
else if (!checked && !checkState.yes) val = ''
handleChangeSearchData({[name]: val})
setCheckState(prevState => ({
'all': prevState.yes && checked,
'yes': prevState.yes,
'no': checked
}))
break;
default:
break;
}
}
return (
<div className='pal-card-box'>
<Row>
<Col>
<div
className='cont-ti d-flex justify-content-between align-items-sm-center align-items-start flex-sm-row'>
<div>
<h4>검색조건</h4>
</div>
</div>
</div>
</dt>
<dt>
<div className='search-box'>
<div className='search-list-ti'>승인여부</div>
<div className='search-list'>
{/* <div className="search-list-cont">
<Input size='sm'/>
</div> */}
<div className='search-list-cont'>
<CustomInput
inline
type='checkbox'
id='exampleCustomCheckbox'
label='전체'
checked={isCheck.all}
onClick={() =>
setIsCheckBox({
all: !isCheck.all,
yes: !isCheck.all,
no: !isCheck.all
})
}
/>
<CustomInput
inline
type='checkbox'
id='exampleCustomCheckbox2'
label='승인'
checked={isCheck.yes || isCheck.all}
onClick={() =>
setIsCheckBox({
all: false,
yes: !isCheck.yes
})
}
/>
<CustomInput
inline
type='checkbox'
id='exampleCustomCheckbox3'
label='미승인'
checked={isCheck.no || isCheck.all}
onClick={() =>
setIsCheckBox({
all: false,
no: !isCheck.no
})
}
/>
<div className='d-flex align-items-center'>
<Button.Ripple
color='primary'
size='sm'
onClick={handleClickSearch}
>
<Search size={16}/>
검색
</Button.Ripple>
</div>
</div>
</div>
</dt>
</dl>
</div>
</CardBody>
</Card>
</Col>
</Row>
</div>
)
<Card>
<CardBody className='pal-card-body'>
<div className='search-cont'>
<dl>
<dt>
<div className='search-box'>
<div className='search-list-ti'>신청일</div>
<div className='search-list'>
<div className='search-list-cont'>
<Row>
<Col className='list-input' xl='4' md='6' sm='12'>
<div className='d-flex align-items-center calendar-flat'>
<Flatpickr
id='searchDate'
value={[
schFltStDt,
schFltEndDt
]}
options={{
mode: 'range',
// defaultDate: [
// props.params.stDate,
// props.params.endDate
// ]
}}
onChange={handleChangeInput}
className='form-control flat-picker bg-transparent border-0 shadow-none'
/>
</div>
</Col>
</Row>
</div>
</div>
</div>
</dt>
<dt>
<div className='search-box'>
<div className='search-list-ti'>승인여부</div>
<div className='search-list'>
<div className='search-list-cont'>
<CustomInput
inline
type='checkbox'
id='exampleCustomCheckbox'
label='전체'
name="aprvlYn"
value="A"
// checked={true}
checked={checkState.all}
onChange={handleChangeCheckbox}
/>
<CustomInput
inline
type='checkbox'
id='exampleCustomCheckbox2'
label='승인'
name="aprvlYn"
value="Y"
checked={checkState.yes}
onChange={handleChangeCheckbox}
/>
<CustomInput
inline
type='checkbox'
id='exampleCustomCheckbox3'
label='미승인'
name="aprvlYn"
value="N"
checked={checkState.no}
onChange={handleChangeCheckbox}
/>
</div>
</div>
</div>
</dt>
</dl>
</div>
</CardBody>
</Card>
</Col>
</Row>
</div>
)
}
export default FlightPlanSearch;
export default FlightPlanSearch;

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

@ -0,0 +1,652 @@
import $ from 'jquery';
import '../../../../assets/css/custom.css';
import { CustomInput } from 'reactstrap';
import buffer from '@turf/buffer'
export const FlightPlanDraw = props => {
const {naver} = props;
const {map} = props;
var Measure = function(buttons) {
this.$btnLine = buttons.line;
this.$btnPolygon = buttons.polygon;
this.$btnCircle = buttons.circle;
this.$btnRectangle = buttons.rectangle;
this._mode = null;
this._bindDOMEvents();
};
$.extend(
Measure.prototype,{
constructor: Measure,
setMap: function(map) {
console.log('setMap')
if (this.map) {
this._unbindMap(this.map);
}
this.map = map;
if (map) {
this._bindMap(map);
}
},
startMode: function(mode) {
console.log('startMode')
if (!mode) return;
if (mode === 'line') {
this._startDistance();
} if (mode === 'polygon') {
this._startArea();
} if (mode === 'circle') {
this._startCircle();
} if (mode === 'rectangle') {
this._startRectangle();
}
},
_startDistance: function() {
console.log('startDistance')
var map = this.map;
this._distanceListeners = [
naver.maps.Event.addListener(map, 'click', this._onClickDistance.bind(this))
];
},
_startArea: function() {
console.log('startArea')
var map = this.map;
this._areaListeners = [
naver.maps.Event.addListener(map, 'click', this._onClickArea.bind(this)),
naver.maps.Event.addListener(map, 'rightclick', this._finishArea.bind(this))
];
$(document).on('mousemove.measure', this._onMouseMoveArea.bind(this));
},
_startCircle: function() {
console.log('startCircle')
var map = this.map;
this._circleListeners = [
naver.maps.Event.addListener(map, 'click', this._onClickCircle.bind(this)),
naver.maps.Event.addListener(map, 'rightclick', this._finishCircle.bind(this))
];
},
_startRectangle: function() {
console.log('startRectangle')
var map = this.map;
this._rectangleListeners = [
naver.maps.Event.addListener(map, 'click', this._onClickRectangle.bind(this)),
naver.maps.Event.addListener(map, 'rightclick', this._finishRectangle.bind(this))
]
},
_finishDistance: function() {
console.log('finishDistance')
naver.maps.Event.removeListener(this._distanceListeners);
delete this._distanceListeners;
$(document).off('mousemove.measure');
if (this._guideline) {
this._guideline.setMap(null);
delete this._guideline;
}
if (this._polyline) {
// console.log(this._polyline.getPath()._array, 'path')
let polypaths = this._polyline.getPath()._array;
//파싱
let polypathJSON = new Array();
for(let i = 0; i< polypaths.length; i++) {
//파싱
let obj = new Object();
obj.x = '' + polypaths[i]._lng + '';
obj.y = '' + polypaths[i]._lat + '';
obj = JSON.stringify(obj);
polypathJSON.push(JSON.parse(obj));
}
console.log(polypathJSON, 'json polyline path')
//버퍼 생성에 필요한 coordinates 배열 변환
let lineStringPaths = [];
for(let i = 0; i < this._polyline.getPath().length; i++) {
lineStringPaths.push([this._polyline.getPath()._array[i].x, this._polyline.getPath()._array[i].y]);
}
console.log(lineStringPaths, 'polyline path')
//버퍼 생성을 위한 line 객체
const originalGeojson = {
type: "FeatureCollection",
features: [
{
type: "Feature",
properties: {},
geometry: {
type: "LineString",
coordinates: lineStringPaths
}
}
]
};
console.log(originalGeojson)
//버퍼 객체
const bufferObj = buffer(originalGeojson, 50, {units:'meters'});
//버퍼 라인 생성
let bufferPath = bufferObj.features[0].geometry.coordinates[0];
console.log(bufferPath, 'buffer path')
this.bufferPolyline = new naver.maps.Polyline({
strokeColor: '#ff0000',
strokeWeight: 2,
strokeStyle: [4, 4],
strokeOpacity: 0.6,
path : bufferPath,
map: map
});
// 이거 하면 그동안 한거 싹 사라짐 -> 얘를 통해서 drawType이 바뀌면 다 날라가는 걸로 해보면 될듯
// this._polyline.setMap(null)
delete this._polyline;
}
//onfocus()의 반대기능 = blur()
this.$btnLine.removeClass('control-on').blur();
this._mode = null;
},
_finishArea: function() {
console.log('finishArea')
naver.maps.Event.removeListener(this._areaListeners);
delete this._areaListeners;
$(document).off('mousemove.measure');
if (this._polygon) {
var path = this._polygon.getPath();
path.pop();
delete this._polygon;
}
this.$btnPolygon.removeClass('control-on').blur();
this._mode = null;
},
_finishCircle: function() {
console.log('finishCircle')
naver.maps.Event.removeListener(this._circleListeners);
delete this._circleListeners;
$(document).off('mousemove.measure');
if(this._guidecircle) {
this._guidecircle.setMap(null);
this._radius.setMap(null);
delete this._raidus;
delete this._guidecircle;
}
if (this._circle) {
// this._circle.setMap(null);
delete this._circle;
}
this.$btnCircle.removeClass('control-on').blur();
// delete this._lastDistance;
this._mode = null;
},
_finishRectangle: function() {
console.log('finishRectangle')
naver.maps.Event.removeListener(this._rectangleListeners);
delete this._rectangleListeners;
$(document).off('mousemove.measure');
if(this._rectangle) {
this._guiderectangle.setMap(null);
delete this._guiderectangle;
}
this.$btnRectangle.removeClass('control-on').blur();
this._mode = null;
},
finishMode: function(mode) {
console.log('finishMode')
if (!mode) return;
if (mode === 'line') {
this._finishDistance();
} if (mode === 'polygon') {
this._finishArea();
} if (mode === 'circle') {
this._finishCircle();
} if (mode === 'rectangle') {
this._finishRectangle();
}
},
_fromMetersToText: function(meters) {
meters = meters || 0;
var km = 1000,
text = meters;
if(meters >= km) {
text = parseFloat((meters / km).toFixed(1)) + 'km';
} else {
text = parseFloat(meters.toFixed(1)) + 'm';
}
return text;
},
_addMileStone: function(coord, text, css) {
if(!this._ms) this._ms = [];
let content;
if(text == 'Start') {
content = '<div style="display:inline-block;padding:5px;text-align:center;background-color:#fff;border:1px solid #000;font-size:14px;color:#ff0000;"><span>'+ text +'</span></div>'
} else {
content = '<div style="display:inline-block;padding:5px;text-align:center;background-color:#fff;border:1px solid #000;color:#737373;"><span>'+ text +'</span></div>'
}
var ms = new naver.maps.Marker({
position: coord,
icon: {
content: content,
anchor: new naver.maps.Point(-5, -5)
},
map: this.map
});
var msElement = $(ms.getElement());
if(css) {
msElement.css(css);
} else {
msElement.css('font-size', '13px');
}
this._ms.push(ms);
},
_onClickDistance: function(e) {
console.log('onClickDistance')
var map = this.map,
coord = e.coord;
if (!this._polyline) {
// 임시로 보여줄 점선 폴리라인을 생성합니다.
this._guideline = new naver.maps.Polyline({
strokeColor: '#0000ff',
strokeWeight: 3,
strokeStyle: [4, 4],
strokeOpacity: 0.2,
path: [coord],
map: map
});
// this._lastDistance = this._guideline.getDistance();
$(document).on('mousemove.measure', this._onMouseMoveDistance.bind(this));
this._distanceListeners.push(naver.maps.Event.addListener(map, 'rightclick', this._finishDistance.bind(this)));
// 실제 거리재기에 사용되는 폴리라인을 생성합니다.
this._polyline = new naver.maps.Polyline({
strokeLineCap: 'round',
strokeLineJoin: 'round',
strokeColor: '#0000ff',
strokeWeight: 3,
strokeOpacity: 0.6,
path: [coord],
map: map
});
this._lastDistance = this._polyline.getDistance();
this._addMileStone(coord, 'Start');
} else {
this._guideline.setPath([e.coord]);
this._polyline.getPath().push(coord);
var distance = this._polyline.getDistance();
this._addMileStone(coord, this._fromMetersToText(distance - this._lastDistance));
this._lastDistance = distance;
}
},
_onMouseMoveDistance: function(e) {
console.log('onMouseMoveDistance')
var map = this.map,
proj = this.map.getProjection(),
coord = proj.fromPageXYToCoord(new naver.maps.Point(e.pageX, e.pageY)),
path = this._guideline.getPath();
if (path.getLength() === 2) {
//맨 뒷 값 삭제 = 기존클릭좌표만 남겨둬라 = 실시간으로 좌표들어가야 하니까
path.pop();
}
// [기존 클릭 좌표, 실시간 좌표]
path.push(coord);
},
_onClickArea: function(e) {
console.log('onClickArea')
var map = this.map,
coord = e.coord;
if (!this._polygon) {
this._polygon = new naver.maps.Polygon({
strokeOpacity: 0.8,
fillColor: '#0000ff',
fillOpacity: 0.1,
paths: [coord],
map: map
});
} else {
this._polygon.getPath().push(coord);
}
},
_onMouseMoveArea: function(e) {
console.log('onMouseMoveArea')
if (!this._polygon) return;
var map = this.map,
proj = this.map.getProjection(),
coord = proj.fromPageXYToCoord(new naver.maps.Point(e.pageX, e.pageY)),
path = this._polygon.getPath();
if (path.getLength() >= 2) {
path.pop();
}
path.push(coord);
},
_onClickCircle: function(e) {
console.log('onClickCircle')
var map = this.map,
coord = e.coord;
if(!this._circle) {
//가이드 라인
this._radius = new naver.maps.Polyline({
strokeStyle: [4, 4],
strokeOpacity: 0.6,
path: [coord],
map: map
});
this._lastDistance = this._radius.getDistance();
// 임시로 보여줄 원형
this._guidecircle = new naver.maps.Circle({
strokeOpacity: 0.8,
strokeStyle: [4, 4],
fillColor: '#0000ff',
fillOpacity: 0.1,
center: coord,
radius: this._lastDistance,
map: map
});
$(document).on('mousemove.measure', this._onMouseMoveCircle.bind(this));
this._circleListeners.push(naver.maps.Event.addListener(map, 'rightclick', this._finishCircle.bind(this)));
// 실제 사용되는 원형
this._circle = new naver.maps.Circle({
strokeOpacity: 0.8,
fillColor: '#0000ff',
fillOpacity: 0.1,
center: coord,
radius: this._lastDistance,
map: map
});
} else {
// this._guidecircle.setCenter(e.coord);
// this._circle.setCenter(coord);
// if(this._radius.getPath().length() === 2) {
// this._radius.getPath().pop();
// }
// this._radius.getPath().push(coord);
var distance = this._radius.getDistance();
this._lastDistance = distance;
this._circle.setRadius(this._lastDistance);
}
},
_onMouseMoveCircle: function(e) {
console.log('onMouseMoveCircle')
if(!this._circle) return;
var map = this.map,
proj = this.map.getProjection(),
coord = proj.fromPageXYToCoord(new naver.maps.Point(e.pageX, e.pageY)),
path = this._radius.getPath(),
center = this._guidecircle.getCenter(), //LatLng으로 나옴
r = proj.getDistance(coord, center);
if(path.getLength() === 2) {
path.pop();
}
path.push(coord);
this._guidecircle.setRadius(r);
},
_onClickRectangle: function(e) {
console.log('onClickRectangle')
var map = this.map,
coord = e.coord;
this.max_x = 0;
this.max_y = 0;
if(!this._rectangle) {
//min = 고정값
this.fixed = coord;
this.min = [this.fixed.x, this.fixed.y];
this.max = [this.max_x, this.max_y];
this.boundscoord = [this.min[0], this.min[1], this.min[0], this.min[1]];
// 임시로 보여줄 사각형
this._guiderectangle = new naver.maps.Rectangle({
strokeStyle: [4, 4],
strokeOpacity: 0.6,
bounds: this.boundscoord,
map: map
});
$(document).on('mousemove.measure', this._onMouseMoveRectangle.bind(this));
this._rectangleListeners.push(naver.maps.Event.addListener(map, 'rightclick', this._finishRectangle.bind(this)));
//실제 사용되는 사각형
this._rectangle = new naver.maps.Rectangle({
strokeOpacity: 0.8,
fillColor: '#0000ff',
fillOpacity: 0.1,
bounds: this.boundscoord,
map: map
});
} else {
this.max = [coord.x, coord.y];
this.boundscoord = [this.min[0], this.min[1], this.max[0], this.max[1]];
this._rectangle.setBounds(this.boundscoord);
}
},
_onMouseMoveRectangle: function(e) {
console.log('onMouseMoveRectangle')
if(!this._rectangle) return;
var map = this.map,
proj = this.map.getProjection(),
coord = proj.fromPageXYToCoord(new naver.maps.Point(e.pageX, e.pageY)),
bounds = this._guiderectangle.getBounds(),
max = [coord.x, coord.y];
this.boundscoord = [this.min[0], this.min[1],max[0], max[1]];
this._guiderectangle.setBounds(this.boundscoord);
},
_bindMap: function(map) {
console.log('bindMap')
},
_unbindMap: function() {
console.log('unbindMap')
this.unbindAll();
},
_bindDOMEvents: function() {
console.log('bindDOMEvents')
this.$btnLine.on('click.measure', this._onClickButton.bind(this, 'line'));
this.$btnPolygon.on('click.measure', this._onClickButton.bind(this, 'polygon'));
this.$btnCircle.on('click.measure', this._onClickButton.bind(this, 'circle'));
this.$btnRectangle.on('click.measure', this._onClickButton.bind(this, 'rectangle'));
},
_onClickButton: function(newMode, e) {
//newMode는 방금 클릭한 값(line, polygon, circle...)
console.log('onClickButton')
e.preventDefault();
var btn = $(e.target),
map = this.map,
mode = this._mode;
//this._mode는 클릭하기 전 값(첫 클릭이면 null)
if (btn.hasClass('control-on')) {
console.log('remove')
btn.removeClass('control-on');
} else {
console.log('add')
btn.addClass('control-on');
}
this._clearMode(mode);
if (mode === newMode) {
this._mode = null;
return;
}
this._mode = newMode;
this.startMode(newMode);
},
_clearMode: function(mode) {
console.log('clearMode')
if (!mode) return;
if (mode === 'line') {
if (this._polyline) {
this._polyline.setMap(null);
delete this._polyline;
}
this._finishDistance();
} else if (mode === 'polygon') {
if (this._polygon) {
this._polygon.setMap(null);
delete this._polygon;
}
this._finishArea();
} else if (mode === 'circle') {
if (this._circle) {
this._circle.setMap(null);
delete this._circle;
}
this._finishCircle();
} else if (mode === 'rectangle') {
if(this._rectangle) {
this._rectangle.setMap(null);
delete this._rectangle;
}
}
}
});
// id랑 매치시켜서 옵션 지정함
var measures = new Measure({
line: $('#line'),
polygon: $('#polygon'),
circle: $('#circle'),
rectangle: $('#rectangle')
});
measures.setMap(map);
return(
<>
<div style={{ position: 'relative' }}>
<ul className="measure-control">
<li>
<CustomInput
id='line'
type='image'
className='control-btn'
src='http://static.naver.net/maps/mantle/drawing/1x/polyline.png'
/>
<CustomInput
id='polygon'
type='image'
className='control-btn'
src='http://static.naver.net/maps/mantle/drawing/1x/polygon.png'
/>
<CustomInput
id='circle'
type='image'
className='control-btn'
src='http://static.naver.net/maps/mantle/drawing/1x/ellipse.png'
/>
<CustomInput
id='rectangle'
type='image'
className='control-btn'
src='http://static.naver.net/maps/mantle/drawing/1x/rectangle.png'
/>
</li>
</ul>
</div>
</>
)
}

676
src/components/map/naver/draw/FlightPlanDrawTest.js

@ -0,0 +1,676 @@
import $ from 'jquery';
import { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
export const FlightPlanDrawTest = props => {
const mapControl = useSelector(state => state.controlMapReducer);
const [pastPolyline, setPolyline] = useState();
const [pastBuffer, setBuffer] = useState();
const [pastPolygon, setPolygon] = useState();
// const [pastCircle, setCircle] = useState();
const [pastCircle, setCircle] = useState([]);
const [pastEve, setEve] = useState();
const [pastDragCircle, setDragCircle] = useState([]);
const [pastMarker, setMarker] = useState([]);
const naver = props.naver;
const map = props.map;
let mode = props.mode;
let areaInfo;
let lastDistance;
let polyline;
let guideline;
let bufferPolygon;
let polygon;
let circle;
let radiusline;
let Eve = {
clickEve: '',
mousedownEve: '',
rightclickEve: ''
}
let dragCircle = [];
let dragCircleEve = [];
let check;
let distanceMarker = [];
useEffect(() => {
drawInit();
}, [mapControl.drawType])
useEffect(() => {
handleDetailDrwa();
}, [props.areaCoordList])
const drawInit = () => {
console.log(mapControl.drawType);
if (mapControl.drawType === 'LINE') {
onClickButton('LINE');
} else if (mapControl.drawType === 'CIRCLE') {
onClickButton('CIRCLE');
} else if (mapControl.drawType === 'POLYGON') {
onClickButton('POLYGON');
} else if (mapControl.drawType === 'RESET') {
onClickReset('RESET')
}
}
const onClickButton = (newMode) => {
console.log('onClickButton');
clearMode(mode);
if (mode === newMode) {
mode = null;
return;
}
// mode = newMode;
startMode(newMode);
}
const clearMode = (mode) => {
console.log('clearMode')
// if(!mode) return;
if (pastPolyline) {
console.log('clear polyline ', pastPolyline)
pastPolyline.setMap(null);
pastDragCircle.forEach(c => c.setMap(null));
pastBuffer.setMap(null);
setPolyline();
setDragCircle([]);
setBuffer();
}
if (pastCircle) {
console.log('clear circle ', pastCircle)
pastCircle.forEach(prev => prev.setMap(null))
naver.maps.Event.removeListener(pastEve);
// setCircle();
setCircle([]);
}
if (pastPolygon) {
console.log('clear polygon ', pastPolygon)
pastPolygon.setMap(null);
pastDragCircle.forEach(c => c.setMap(null));
setPolygon();
setDragCircle([]);
}
if (pastMarker) {
console.log('clear marker ', pastMarker)
pastMarker.forEach(m => m.setMap(null));
}
finishDraw();
props.handleInitCoordinates();
}
const startMode = (mode) => {
console.log('startMode')
if (!mode) return;
if (mode === 'LINE') {
Eve.clickEve = naver.maps.Event.addListener(map, 'click', function (e) { onClickPolyline(e) });
} else if (mode === 'POLYGON') {
Eve.clickEve = naver.maps.Event.addListener(map, 'click', function (e) { onClickPolygon(e) });
} else if (mode === 'CIRCLE') {
setEve(naver.maps.Event.addListener(map, 'click', function (e) { onClickCircle(e) }))
}
}
const removeListener = () => {
console.log('removeListener')
naver.maps.Event.removeListener(Eve.clickEve);
naver.maps.Event.removeListener(Eve.mousedownEve);
naver.maps.Event.removeListener(Eve.rightclickEve);
if (!circle) $(document).off('mousemove.measure');
// if(pastCircle) naver.maps.Event.removeListener(pastEve);
naver.maps.Event.removeListener(pastEve);
}
const finishDraw = () => {
console.log('finishDraw')
removeListener();
if (polyline) {
if (guideline) {
guideline.setMap(null);
guideline = '';
}
let polypaths = polyline.getPath()._array;
if (polypaths.length >= 2) {
setPolyline(polyline);
setAreaInfo(polypaths);
} else {
polyline.setMap(null);
polyline = '';
}
polyline.setMap(null)
} else if (polygon) {
let path = polygon.getPath();
path.pop();
let polygonpaths = polygon.getPath()._array;
setPolygon(polygon);
setAreaInfo(polygonpaths);
polygon.setMap(null)
}
}
const onClickPolyline = (e) => {
console.log('onClickPolyline')
var coord = e.coord;
// if (!check) {
if (!polyline) {
//가이드라인
guideline = new naver.maps.Polyline({
strokeColor: '#283046',
strokeWeight: 2,
strokeOpacity: 0.3,
path: [coord],
map: map
});
lastDistance = guideline.getDistance();
//실제 사용되는 라인
polyline = new naver.maps.Polyline({
strokeLineCap: 'round',
strokeLineJoin: 'round',
// strokeColor: '#283046',
strokeColor: '#ff0000',
strokeWeight: 3,
strokeOpacity: 1,
path: [coord],
map: map
});
Eve.rightclickEve = naver.maps.Event.addListener(map, 'rightclick', function () { finishDraw() })
$(document).on('mousemove.measure', function (e) { onMouseMovePolyline(e); });
lastDistance = polyline.getDistance();
addMileStone(coord, 'Start')
} else {
guideline.setPath([e.coord]);
polyline.getPath().push(coord);
var distance = polyline.getDistance();
addMileStone(coord, fromMetersToText(distance - lastDistance));
lastDistance = distance;
}
// }
}
const onMouseMovePolyline = (e) => {
console.log('onMouseMovePolyline')
var proj = map.getProjection(),
coord = proj.fromPageXYToCoord(new naver.maps.Point(e.pageX, e.pageY)),
path = guideline.getPath();
if (path.getLength() === 2) {
path.pop();
}
path.push(coord);
}
const onClickPolygon = (e) => {
console.log('onClickPolygon')
var coord = e.coord;
if (!polygon) {
polygon = new naver.maps.Polygon({
strokeColor: '#283046',
strokeOpacity: 1,
fillColor: '#7367F0',
fillOpacity: 0.1,
paths: [coord],
map: map
});
Eve.rightclickEve = naver.maps.Event.addListener(map, 'rightclick', function () { finishDraw() })
$(document).on('mousemove.measure', function (e) { onMouseMovePolygon(e) });
} else {
polygon.getPath().push(coord);
}
}
const onMouseMovePolygon = (e) => {
console.log('onMouseMovePolygon')
if (!polygon) return;
var proj = map.getProjection(),
coord = proj.fromPageXYToCoord(new naver.maps.Point(e.pageX, e.pageY)),
path = polygon.getPath();
if (path.getLength() >= 2) {
path.pop();
}
path.push(coord);
}
const onClickCircle = (e) => {
console.log('onClickCircle')
var coord = e.coord;
if(!circle) {
radiusline = new naver.maps.Polyline({
strokeStyle: [4, 4],
strokeOpacity: 0.6,
path: [coord],
map: map
})
lastDistance = radiusline.getDistance();
circle = new naver.maps.Circle({
strokeColor: '#283046',
strokeOpacity: 1,
fillColor: '#7367F0',
fillOpacity: 0.1,
center: coord,
radius: 100,
// map: map,
clickable: true
})
Eve.mousedownEve = naver.maps.Event.addListener(circle, 'mousedown', function () { onMouseDownDrag(0); })
} else {
circle.setCenter(coord);
circle.setRadius(100);
}
// setCircle(circle);
setCircle(prev => ([...prev, circle]))
setAreaInfo('');
}
const onMouseDownDrag = (index) => {
console.log('onMouseDownDrag')
if (circle) {
naver.maps.Event.removeListener(Eve.clickEve);
}
map.setOptions({
draggable: false,
pinchZoom: false,
scrollWheel: false,
keyboardShortcuts: false,
disableDoubleTapZoom: true,
disableDoubleClickZoom: true,
disableTwoFingerTapZoom: true
})
$(document).on('mousemove.measure', function (e) { onMouseMoveDrag(e, index) });
$(document).on('mouseup.measure', function () { onMouseUpDrag() });
}
const onMouseMoveDrag = (e, index) => {
console.log('onMouseMoveDrag')
check = true;
var proj = map.getProjection(),
coord = proj.fromPageXYToCoord(new naver.maps.Point(e.pageX, e.pageY));
if (polyline) {
var polypaths = polyline.getPath()._array;
let movepath = [];
for (let i = 0; i < polypaths.length; i++) {
let path;
if (i === index) {
path = coord;
} else {
path = polypaths[i]
}
movepath.push(path);
}
polyline.setPath(movepath);
} else if (polygon) {
var polygonpaths = polygon.getPath()._array;
let movepath = [];
for (let i = 0; i < polygonpaths.length; i++) {
let path;
if (i === index) {
path = coord;
} else {
path = polygonpaths[i]
}
movepath.push(path);
}
polygon.setPaths(movepath)
} else if (circle) {
// var circlepath = radiusline.getPath(),
// center = circle.getCenter(),
// r = proj.getDistance(coord, center);
var center = circle.getCenter(),
r = proj.getDistance(coord, center);
// if (circlepath.getLength() === 2) {
// circlepath.pop();
// }
// circlepath.push(coord);
circle.setRadius(r);
}
if (!circle) {
dragCircle[index].setCenter(coord);
}
}
const onMouseUpDrag = () => {
console.log('onMouseUpDrag')
map.setOptions({
draggable: true,
pinchZoom: true,
scrollWheel: true,
keyboardShortcuts: true,
disableDoubleTapZoom: false,
disableDoubleClickZoom: false,
disableTwoFingerTapZoom: false
})
if (polyline) {
var path = polyline.getPath()._array;
setPolyline(polyline);
setAreaInfo(path);
props.handleBufferList();
}
if (polygon) {
var path = polygon.getPath()._array;
setPolygon(polygon);
setAreaInfo(path);
}
$(document).off('mousemove.measure');
$(document).off('mouseup.measure');
if (circle) {
// Eve.clickEve = naver.maps.Event.addListener(map, 'click', function(e) { onClickCircle(e); })
setEve(naver.maps.Event.addListener(map, 'click', function (e) { onClickCircle(e) }))
// setCircle(circle);
setCircle(prev => ([...prev, circle]))
setAreaInfo('');
}
check = false;
}
const setAreaInfo = (path) => {
areaInfo = {
coordinates: [],
bufferZone: 0,
};
let prePath = [];
if (path) {
path.forEach((item) => {
const p = {
lat: item.y,
lon: item.x
}
prePath.push(p);
})
// path.forEach(prev=> prePath.push([prev.x, prev.y]))
}
if (polyline) {
areaInfo.coordinates = prePath;
areaInfo.areaType = 'LINE';
} else if (polygon) {
areaInfo.coordinates = prePath;
areaInfo.areaType = 'POLYGON';
} else if (circle) {
const point = {
lat: circle.getCenter().y,
lon: circle.getCenter().x
}
areaInfo.coordinates.push(point);
areaInfo.bufferZone = circle.getRadius();
areaInfo.areaType = 'CIRCLE';
}
props.handleCoordinates(areaInfo);
// console.log(areaInfo, 'areaInfo')
}
const onClickReset = () => {
console.log('onClickRest - ', mapControl.drawType);
if (mapControl.drawType === 'RESET') {
clearMode('RESET');
}
}
const handleDetailDrwa = () => {
if (props.areaCoordList) {
console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
const areas = props.areaCoordList[0];
const paths = [];
areas.coordList.forEach((coord) => {
const path = new naver.maps.LatLng(coord.lat, coord.lon)
paths.push(path);
});
if (areas.areaType && areas.areaType === 'LINE') {
//polyline 생성
if(pastPolyline) {
pastPolyline.setMap(null);
pastDragCircle.forEach(c => c.setMap(null));
}
polyline = new naver.maps.Polyline({
strokeLineCap: 'round',
strokeLineJoin: 'round',
strokeColor: '#283046',
strokeWeight: 3,
strokeOpacity: 1,
path: paths,
map: map
});
setPolyline(polyline)
//dragCircle 생성
for(let i = 0; i < paths.length; i++) {
dragCircle.push(
new naver.maps.Circle({
strokestrokeOpacity: 1,
strokeColor: '#000000',
fillColor: '#ffffff',
fillOpacity: 1,
center: paths[i],
radius: 15,
map: map,
clickable: true
})
)
dragCircleEve.push(naver.maps.Event.addListener(dragCircle[i], 'mousedown', function () { onMouseDownDrag(i) }))
}
setDragCircle(dragCircle);
if (areas.bufferCoordList) {
const bufferPaths = [];
areas.bufferCoordList.forEach((bfCoord) => {
const path = new naver.maps.LatLng(bfCoord.lat, bfCoord.lon);
bufferPaths.push(path);
});
console.log('buffer test : ',areas.bufferCoordList);
if(pastBuffer) {
pastBuffer.setMap(null);
}
// console.log(bufferPaths)
//bufferline 생성
bufferPolygon = new naver.maps.Polyline({
strokeColor: '#283046',
strokeOpacity: 1,
// fillColor: '#7367F0',
// fillOpacity: 0.1,
path: bufferPaths,
map: map
});
// console.log(bufferPolygon);
setBuffer(bufferPolygon);
}
}
if (areas.areaType && areas.areaType === 'POLYGON') {
//polygon 생성
if(pastPolygon) {
pastPolygon.setMap(null);
pastDragCircle.forEach(c => c.setMap(null));
}
polygon = new naver.maps.Polygon({
strokeColor: '#283046',
strokeOpacity: 1,
fillColor: '#7367F0',
fillOpacity: 0.1,
paths: paths,
map: map
});
setPolygon(polygon);
//dragCircle 생성
for(let i = 0; i < paths.length; i++) {
dragCircle.push(
new naver.maps.Circle({
strokestrokeOpacity: 1,
strokeColor: '#000000',
fillColor: '#ffffff',
fillOpacity: 1,
center: paths[i],
radius: 15,
map: map,
clickable: true
})
)
dragCircleEve.push(naver.maps.Event.addListener(dragCircle[i], 'mousedown', function () { onMouseDownDrag(i) }))
}
setDragCircle(dragCircle);
}
if (areas.areaType && areas.areaType === 'CIRCLE') {
//circle 생성
if(pastCircle) {
// pastCircle.setMap(null);
console.log(pastCircle)
pastCircle.forEach(prev => prev.setMap(null));
}
if(circle) {
circle.setMap(null);
}
// radiusline = new naver.maps.Polyline({
// strokeStyle: [4, 4],
// strokeOpacity: 0.6,
// path: [coord],
// map: map
// })
circle = new naver.maps.Circle({
strokeColor: '#283046',
strokeOpacity: 1,
// fillColor: '#ff0000',
fillColor: '#7367F0',
fillOpacity: 0.1,
center: paths[0],
radius: areas.bufferZone,
map: map,
clickable: true
});
Eve.mousedownEve = naver.maps.Event.addListener(circle, 'mousedown', function () { onMouseDownDrag(0); })
setCircle([circle]);
}
}
}
const addMileStone = (coord, text, css) => {
if(distanceMarker) distanceMarker = [];
let content;
if(text == 'Start') {
content = '<div style="display:inline-block;padding:5px;text-align:center;background-color:#fff;border:1px solid #000;font-size:14px;color:#ff0000;"><span>'+ text +'</span></div>'
} else {
content = '<div style="display:inline-block;padding:5px;text-align:center;background-color:#fff;border:1px solid #000;color:#737373;"><span>'+ text +'</span></div>'
}
var _ms = new naver.maps.Marker({
position: coord,
icon: {
content: content,
anchor: new naver.maps.Point(-5, -5)
},
map: map
});
var msElement = $(_ms.getElement());
if(css) {
msElement.css(css);
} else {
msElement.css('font-size', '13px');
}
distanceMarker.push(_ms);
setMarker(prev => ([...prev, _ms]))
}
const fromMetersToText = (meters) => {
meters = meters || 0;
var km = 1000,
text = meters;
if(meters >= km) {
text = parseFloat((meters / km).toFixed(1)) + 'km';
} else {
text = parseFloat(meters.toFixed(1)) + 'm';
}
return text;
}
return (
<>
</>
);
};

2
src/components/mapDraw/naver/draw/JQueryDraw.js

@ -2,8 +2,6 @@ import $ from 'jquery';
import '../../../../assets/css/custom.css';
import { CustomInput } from 'reactstrap';
import buffer from '@turf/buffer'
export const JQueryDraw = props => {
const {naver} = props;
const {map} = props;

45
src/containers/basis/flight/plan/FlightPlanArcrftContainer.js

@ -0,0 +1,45 @@
import React, {useEffect, useState} from 'react';
import {useDispatch, useSelector} from 'react-redux';
import FlightPlanArcrft from '../../../../components/basis/flight/plan/FlightPlanArcrft';
import * as Actions from '../../../../modules/basis/flight/actions/basisFlightAction';
// import FlightPlanPilot from '../../../../components/basis/flight/plan/FlightPlanPilot';
const FlightPlanArcrftContainer = ({handleModal, type}) => {
const dispatch = useDispatch();
const { arcrftList } = useSelector(state => state.flightState);
/* 기체 조회 */
const handleSearch = () => {
const groupId = sessionStorage.getItem('groupId');
if(groupId) {
dispatch(Actions.FLIGHT_PLAN_ARCRFT_LIST.request(groupId));
}
}
/* 기체 선택 */
const handleSelectArcrft = (arcrftSno) => {
handleModal({target: 'arcrft', isOpen: false});
const arcrft = arcrftList.find(arcrft => {
return arcrft.arcrftSno === arcrftSno;
});
/* 기체 정보 Redux 저장 */
dispatch(Actions.ARCRFT_SELECT(arcrft));
}
useEffect(() => {
handleSearch();
}, [])
return (
<FlightPlanArcrft
arcrftList = {arcrftList}
handleSelectArcrft={handleSelectArcrft}
/>
)
}
export default FlightPlanArcrftContainer;

83
src/containers/basis/flight/plan/FlightPlanAreaContainer.js

@ -2,74 +2,61 @@ import React, { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import {useHistory} from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import FlightPlanAreaForm from '../../../../components/basis/flight/plan/FlightPlanAreaForm';
import {Col, Row, Form } from 'reactstrap';
import * as Actions from '../../../../modules/basis/flight/actions/basisFlightAction';
import FlightPlanAreaMap from '../../../../components/basis/flight/plan/FlightPlanAreaMap';
import * as yup from 'yup';
import { yupResolver } from '@hookform/resolvers/yup';
import { drawTypeChangeAction } from '../../../../modules/control/map/actions/controlMapActions';
import FlightPlanAreaDetailContainer from './FlightPlanAreaDetailContainer';
const FlightPlanAreaContainer = (props) => {
const dispatch = useDispatch();
const history = useHistory();
const { areaList } = useSelector(state => state.flightState);
const [airArea, setAirArea] = useState(null);
const validSchema = yup.object().shape({
});
const { register, getValues, setValue, errors, handleSubmit } = useForm({
defaultValues: {
coodinates: [],
radius: '',
altitude_m: '',
altitude_ft: '',
},
resolver: yupResolver(validSchema)
});
const FlightPlanAreaContainer = ({handleModal}) => {
const dispatch = useDispatch();
const { publicAreaList} = useSelector(state => state.flightState);
const [airArea, setAirArea] = useState(null);
const getAirAreaList = () => {
dispatch(Actions.AREA_LIST.request());
}
const createAirArea = async data => {
dispatch(Actions.FLIGHT_PLAN_AREA.request(data));
props.setModal({ ...props.modal, isOpen: !props.modal.isOpen });
props.setOnSubmit(false);
dispatch(Actions.PUBLIC_AREA_LIST.request());
}
const handleConfirm = (areaList) => {
if(areaList === undefined) {
alert('영역을 설정해주세요.')
return false;
}
dispatch(Actions.AREA_COORDINATE_LIST_SAVE(areaList))
}
useEffect(() => {
useEffect(() => {
dispatch(drawTypeChangeAction(''));
getAirAreaList();
}, []);
useEffect(() => {
setAirArea(areaList);
}, [areaList])
useEffect(() => {
setAirArea(publicAreaList);
}, [publicAreaList])
return (
return (
<Row>
<Col md={6} lg={6}>
{airArea != null ? (
<FlightPlanAreaMap
airArea={airArea}
airArea={airArea}
handleConfirm={handleConfirm}
/>
) : null}
</Col>
<Col md={6} lg={6}>
<FlightPlanAreaForm
modal={props.modal}
setModal={props.setModal}
data={register}
errors={errors}
submit={handleSubmit(createAirArea)}
/>
</Col>
</Row>
) : null}
</Col>
<Col md={6} lg={6}>
<FlightPlanAreaDetailContainer
handleModal={handleModal}
/>
</Col>
</Row>
)
}
export default FlightPlanAreaContainer;
export default FlightPlanAreaContainer;

86
src/containers/basis/flight/plan/FlightPlanAreaDetailContainer.js

@ -0,0 +1,86 @@
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Col, Row, Form } from 'reactstrap';
import * as Actions from '../../../../modules/basis/flight/actions/basisFlightAction';
import FlightPlanAreaDetailForm from '../../../../components/basis/flight/plan/FlightPlanAreaDetailForm';
import {initFlightBas} from '../../../../modules/basis/flight/models/basisFlightModel';
const FlightPlanAreaDetailContainer = ({ handleModal }) => {
const dispatch = useDispatch();
const { areaCoordList, detail } = useSelector(state => state.flightState);
const [areaDetail, setAreaDetail] = useState(initFlightBas.initDetail.areaList);
const handleClose = (status) => {
handleModal({ type: 'area', isOpne: false});
}
const handleSave = () => {
const resultAreaDetail = areaDetail.map((area, i) => {
return {
...area,
coordList : areaDetail[0].coordList
}
});
dispatch(Actions.AREA_DETAIL_LIST_SAVE(resultAreaDetail));
handleModal({ type: 'area', isOpne: false});
}
const handleChange = ({ name, value }) => {
setAreaDetail(prevState => {
const areaList = prevState.map((area, i) => {
return {
...area,
[name] : value
}
});
return areaList;
})
}
const handleBufferList = () => {
dispatch(Actions.FLIGHT_PLAN_AREA_BUFFER_LIST.request(areaDetail));
}
useEffect(() => {
// 좌표등록 (등록 시 데이터 초기화)
if(areaCoordList !== undefined) {
setAreaDetail(areaCoordList); // 새로 만든 영역
}
}, [areaCoordList]);
useEffect(() => {
// detail의 area 정보가 존재하면 detail 정보로 매핑
if(detail.areaList) {
if(detail.areaList[0].planAreaSno !== 0) {
setAreaDetail(detail.areaList);
dispatch(Actions.AREA_DETAIL_LIST_SAVE(detail.areaList));
}
}
}, [])
return (
<Row>
<Col>
<FlightPlanAreaDetailForm
handleClose={handleClose}
handleSave={handleSave}
handleChange={handleChange}
handleBufferList={handleBufferList}
areaCoordList={areaCoordList}
data={areaDetail}
/>
</Col>
</Row>
)
}
export default FlightPlanAreaDetailContainer;

140
src/containers/basis/flight/plan/FlightPlanContainer.js

@ -1,38 +1,138 @@
import React, { useState } from 'react';
import moment from 'moment';
import { Link, useHistory } from 'react-router-dom';
import React, {useEffect, useState} from 'react';
import moment, { suppressDeprecationWarnings } from 'moment';
import {Link, Redirect, useHistory} from 'react-router-dom';
import FlightPlanGrid from '../../../../components/basis/flight/plan/FlightPlanGrid';
import { CustomMainLayout } from '../../../../components/layout/CustomMainLayout';
import {CustomMainLayout} from '../../../../components/layout/CustomMainLayout';
import FlightPlanSearch from '../../../../components/basis/flight/plan/FlightPlanSearch';
import {useDispatch, useSelector, shallowEqual} from 'react-redux';
import * as FlightAction from '../../../../modules/basis/flight/actions/basisFlightAction';
import {FlightPlanListRqData} from '../../../../modules/basis/flight/models/basisFlightModel';
import { Row, Col } from 'reactstrap';
import { JOIN_LIST } from "../../../../modules/basis/group/actions/basisGroupAction";
import FlightPlanGroupGrid from '../../../../components/basis/flight/plan/FlightPlanGroupGrid';
const FlightPlanContainer = () => {
const initSearchData = {
schFltStDt: moment().set({'m': 7, 'date': 1, 'h': 0, 'm': 0, 's': 0}).format('YYYY-MM-DD HH:mm:ss'),
schFltEndDt: moment().set({'h': 23, 'm': 59, 's': 59}).format('YYYY-MM-DD HH:mm:ss'),
aprvlYn: 'N',
groupId: '',
cstmrSno: 0,
}
const columns = [{}]
const FlightPlanContainer = () => {
const dispatch = useDispatch();
const history = useHistory();
const [searchData, setSerchData] = useState(initSearchData);
const {list: planListData, detail: planDetailData, selectGroup, areaCoordList } = useSelector(state => state.flightState);
const { joinList, joinListCount } = useSelector(state => state.groupState);
const { user } = useSelector(state => state.authState, shallowEqual);
const moveFlightPlan = () => {
const [ params, setParams ] = useState({});
const moveFlightPlanDetailPage = () => {
if(planDetailData){
dispatch(FlightAction.FLIGHT_PLAN_DETAIL_INIT());
}
if(areaCoordList) {
dispatch(FlightAction.AREA_DETAIL_INIT());
}
history.push('/basis/flight/plan/create');
};
const [times, setTimes] = useState({
stDate: moment().subtract(1, 'day').format('YYYY-MM-DD'),
endDate: moment().subtract(-1, 'day').format('YYYY-MM-DD'),
search1: ''
})
const handleSearch = (data) => {
dispatch(FlightAction.FLIGHT_PLAN_LIST.request(data));
}
const handleChangeSearchData = (values) => {
setSerchData(prevState => ({
...prevState,
...values
}))
}
const handleMoveDetail = (id) => {
history.push(`/basis/flight/plan/detail/${id}`)
}
const handleGroupSelect = ({ groupId, groupNm, groupAuthCd }) => {
// 권한 상관 없이 모두 조회 가능
console.log('select group : ', groupId)
const param = searchData;
param.cstmrSno = user.cstmrSno;
param.groupId = groupId;
dispatch(FlightAction.FLIGHT_PLAN_GROUP_SELECT( {cstmrSno: user.cstmrSno, groupId: groupId, groupNm: groupNm} ));
// groupId sessionStorage에 보관 (1 브라우저 1 tab에만 유효)
sessionStorage.setItem('groupId', groupId);
setSerchData(prevState => {
return {
...prevState,
cstmrSno: user.cstmrSno,
groupId: groupId
}
});
dispatch(FlightAction.FLIGHT_PLAN_LIST.request(param));
}
// console.log(history, 'history')
const handlerGroupCancel = () => {
dispatch(FlightAction.FLIGHT_PLAN_GROUP_SELECT( {cstmrSno: 0, groupId: '', groupNm: ''} ));
}
useEffect(() => {
if (user?.cstmrSno) {
dispatch(
JOIN_LIST.request({
cstmrSno: user?.cstmrSno
})
);
}
}, [user])
return (
// <CustomMainLayout title={"비행 계획 관리"}>
<CustomMainLayout title={"비행계획서 신청"}>
<FlightPlanSearch
params={times}
/>
<FlightPlanGrid
moveFlightPlan={moveFlightPlan}
/>
<div className='pal-card-box'>
<Row>
<Col sm='4'>
<FlightPlanGroupGrid
data = {joinList}
count = {joinListCount}
selectGroup = {selectGroup}
handleGroupSelect = {handleGroupSelect}
handlerGroupCancel = {handlerGroupCancel}
/>
</Col>
<Col sm='8'>
{selectGroup.cstmrSno !== 0 ? (
<>
<FlightPlanSearch
searchData={searchData}
handleChangeSearchData={handleChangeSearchData}
handleSearch={handleSearch}
/>
<FlightPlanGrid
movePage={moveFlightPlanDetailPage}
planListData={planListData}
columns={columns}
handleMoveDetail={handleMoveDetail}
/>
</>
) : (
<div className='no-dataTable'>
나의 그룹 목록에서 상세보기를 클릭하세요.
</div>
)}
</Col>
</Row>
</div>
</CustomMainLayout>
)
}
export default FlightPlanContainer;
export default FlightPlanContainer;

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

@ -1,68 +1,377 @@
import React, {useEffect, useState} from 'react';
import FlightPlanForm from '../../../../components/basis/flight/plan/FlightPlanForm';
import { CustomDetailLayout } from '../../../../components/layout/CustomDetailLayout';
import { FlightPlanAreaModal } from '../../../../components/basis/flight/plan/FlightPlanAreaModal';
import FlightPlanAreaContainer from './FlightPlanAreaContainer';
import {useHistory} from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import * as yup from 'yup';
import { yupResolver } from '@hookform/resolvers/yup';
import {CustomDetailLayout} from '../../../../components/layout/CustomDetailLayout';
import {useHistory, useLocation, useParams} from 'react-router-dom';
import {useDispatch, useSelector} from 'react-redux';
import * as Actions from '../../../../modules/basis/flight/actions/basisFlightAction';
import { useForm } from 'react-hook-form';
import {initFlightBas} from '../../../../modules/basis/flight/models/basisFlightModel';
const initModal = {
area: false,
pilot: false,
arcrft: false
}
const FlightPlanDetailContainer = () => {
const dispatch = useDispatch();
const history = useHistory();
const { flightPlanArea } = useSelector(state => state.flightState);
const [areaInfo, setAreaInfo] = useState();
const [modal, setModal] = useState({
isOpen: false,
title: '',
});
/* Form Validation Checking */
const validSchema = yup.object().shape({
});
const {} = useForm({
defaultValues: {
coodinates: [],
radius: '',
altitude_m: '',
altitude_ft: '',
},
resolver: yupResolver(validSchema)
})
const saveFlightPlanArea = () => {
console.log('비행 구역 설정 저장');
}
const location = useLocation();
const urlParams = useParams();
const flightState = useSelector(state => state.flightState);
const { detail, pilotSelect, arcrftSelect, areaList, selectGroup } = flightState;
const [modal, setModal] = useState(initModal);
const [detailData, setDetailData] = useState(initFlightBas.initDetail);
useEffect(() => {
if (Object.keys(urlParams).length === 0 && urlParams.constructor === Object) return;
dispatch(Actions.FLIGHT_PLAN_DETAIL.request(urlParams.planSno));
}, [urlParams])
const openModal = () => {
setModal({
isOpen: true,
title: '비행 구역 설정',
useEffect(() => {
setDetailData({
...detail,
cstmrSno: selectGroup.cstmrSno,
groupId: selectGroup.groupId,
});
}
}, [detail])
useEffect(() => {
if(pilotSelect !== undefined) {
const pilotList = detailData.pilotList.concat();
const pilot = Object.assign({}, initFlightBas['pilot']);
pilot.cstmrSno = pilotSelect.cstmrSno;
pilot.groupNm = pilotSelect.groupNm;
pilot.clncd = pilotSelect.clncd;
pilot.email = pilotSelect.email;
pilot.memberName = pilotSelect.memberName;
pilot.hpno = pilotSelect.hpno;
pilotList.forEach((p, i) => {
if(p.cstmrSno === 0) {
pilotList[i] = pilot
} else {
if(i === pilotList.length-1) {
return pilotList.push(pilot);
}
}
});
setDetailData(prevState => {
return {
...prevState,
['pilotList']: pilotList
}
})
}
}, [pilotSelect])
useEffect(() => {
if(arcrftSelect !== undefined) {
const arcrftList = detailData.arcrftList.concat();
const arcrft = Object.assign({}, initFlightBas['arcrft']);
arcrft.arcrftSno = arcrftSelect.arcrftSno;
arcrft.groupId = arcrftSelect.groupId;
arcrft.groupNm = arcrftSelect.groupNm;
arcrft.arcrftModelNm = arcrftSelect.arcrftModelNm;
arcrft.idntfTypeCd = arcrftSelect.idntfTypeCd;
arcrft.arcrftTypeCd = arcrftSelect.arcrftTypeCd;
arcrft.idntfNum = arcrftSelect.idntfNum;
arcrft.ownerNm = arcrftSelect.ownerNm;
arcrftList.forEach((p, i) => {
if(p.arcrftSno === 0) {
arcrftList[i] = arcrft
} else {
if(i === arcrftList.length-1) {
return arcrftList.push(arcrft);
}
}
});
setDetailData(prevState => {
return {
...prevState,
['arcrftList']: arcrftList
}
})
}
}, [arcrftSelect])
useEffect(() => {
if(areaList !== undefined) {
const areas = detailData.areaList.concat();
const createAreaList = areas.map((area, i) => {
const targetArea = areaList[i];
let targetCoordList = area.coordList;
if(targetArea.coordList) {
targetCoordList = targetArea.coordList.map((coord, j) => {
return {
...coord,
planAreaSno : area.planAreaSno,
planAreaCoordSno : 0
}
})
}
return {
...area,
areaType : targetArea.areaType,
bufferZone: targetArea.bufferZone,
fltElev : targetArea.fltElev,
fltMethod : targetArea.fltMethod,
coordList : targetCoordList
}
});
setDetailData(prevState => {
return {
...prevState,
['areaList']: createAreaList
}
})
// dispatch(Actions.AREA_DETAIL_INIT());
}
}, [areaList]);
useEffect(() => {
setAreaInfo(flightPlanArea);
}, [flightPlanArea]);
// 조종사, 기체 정보 Redux 초기화
dispatch(Actions.PILOT_ARCRFT_SELECT_INIT());
}, []);
const handleModal = (modal) => {
if(modal.target === 'area' && modal.isOpen) {
if(detailData.areaList) {
dispatch(Actions.FLIGHT_PLAN_AREA_BUFFER_LIST.request(detailData.areaList));
}
}
setModal(prevState => ({
...initModal,
[modal.target]: modal.isOpen
}))
}
// 변경감지
const handleChange = ({name, value, type, index, pIndex}) => {
const arrName = `${type}List`;
switch (type) {
case 'coord':
// TODO 추후 삭제 필요 start
if(name == 'lonlat'){
const values = value.split("/");
let latValue = 1
let lonValue = 1
if(values.length == 1){
latValue = values[0].trim();
} else if(values.length == 2){
latValue = values[0].trim();
lonValue = values[1].trim();
} else {
return;
}
setDetailData(prevState => {
const areaList = prevState.areaList.map((area, i) => {
if(i !== pIndex) return {...area};
const coordList = area.coordList.map((coord, j) => {
if(j !== index) return {...coord};
return {
...coord,
lat: latValue,
lon: lonValue
}
})
return {
...area,
coordList
}
})
return {
...prevState,
areaList
}
})
return;
}
// TODO 추후 삭제 필요 end
setDetailData(prevState => {
const areaArr = [...prevState.areaList];
const coordArr = areaArr[pIndex].coordList;
const updateData = {
...coordArr[index],
[name]: value
}
coordArr[index] = updateData;
areaArr[pIndex] = coordArr
return {
...prevState,
areaList: areaArr
}
})
break;
case 'area':
case 'pilot':
case 'arcrft':
setDetailData(prevState => {
const arr = [...prevState[arrName]];
const updateData = {
...prevState[arrName][index],
[name]: value
}
arr[index] = updateData;
return {
...prevState,
[arrName]: arr
}
})
break;
case 'plan':
default:
setDetailData(prevState => ({
...prevState,
[name]: value
}))
break;
}
}
// 추가
const handleAddArray = ({type, pIndex}) => {
const arrName = `${type}List`;
switch (type) {
case 'coord':
setDetailData(prevState => {
const areaArr = [...prevState.areaList];
const coordArr = [...areaArr[pIndex].coordList, initFlightBas[type]];
areaArr[pIndex] = coordArr;
return {
...prevState,
areaList: [...areaArr]
}
})
break;
case 'area':
case 'pilot':
setDetailData(prevState => {
return {
...prevState,
[arrName]: [...prevState[arrName], initFlightBas[type]]
}
})
break;
case 'arcrft':
setDetailData(prevState => {
return {
...prevState,
[arrName]: [...prevState[arrName], initFlightBas[type]]
}
})
break;
default:
break;
}
}
// 삭제
const handleDeleteArray = ({type, index, pIndex}) => {
const arrName = `${type}List`;
switch (type) {
case 'coord':
setDetailData(prevState => {
const areaArr = [...prevState.areaList];
const coordArr = [...areaArr[pIndex]];
const deleteData = coordArr.splice(index, 1);
areaArr[pIndex] = coordArr;
return {
...prevState,
areaList: [...areaArr]
}
})
break;
case 'area':
case 'pilot':
setDetailData(prevState => {
const arr = [...prevState[arrName]];
const deleteData = arr.splice(index, 1);
return {
...prevState,
[arrName]: arr
}
})
case 'arcrft':
setDetailData(prevState => {
const arr = [...prevState[arrName]];
const deleteData = arr.splice(index, 1);
if(arr.length > 0) {
return {
...prevState,
[arrName]: arr
}
} else {
return {
...prevState,
['pilotList']: initFlightBas[arrName]
}
}
})
default:
break;
}
}
// 저장
const handleSave = () => {
if (!detailData.planSno) {
dispatch(Actions.FLIGHT_PLAN_CREATE.request(detailData));
} else {
dispatch(Actions.FLIGHT_PLAN_UPDATE.request(detailData));
}
dispatch(FlightAction.FLIGHT_PLAN_GROUP_SELECT( {cstmrSno: 0, groupId: '', groupNm: ''} ));
}
// 삭제
const handleDelete = () => {
dispatch(Actions.FLIGHT_PLAN_DELETE.request(urlParams.planSno));
}
return (
<CustomDetailLayout title={"비행 계획 신청서"}>
<FlightPlanForm
openModal={openModal}
areaInfo={areaInfo}
/>
<FlightPlanAreaModal
modal={modal}
save={saveFlightPlanArea}
setModal={setModal}
/>
data={detailData}
handleModal={handleModal}
handleSave={handleSave}
handleDelete={handleDelete}
handleChange={handleChange}
handleAddArray={handleAddArray}
handleDeleteArray={handleDeleteArray}
// handlerSave={
// pageType === 'create' ? handlerCreate : handlerUpdate
// }
// onChange={onChange}
// handlerDelete={handlerDelete}
// handlerInput={handlerInput}
/>
{/*<FlightPlanAreaModal*/}
{/* modal={modal}*/}
{/* save={saveFlightPlanArea}*/}
{/* setModal={setModal}*/}
{/*/>*/}
</CustomDetailLayout>
)
};
}
export default FlightPlanDetailContainer;
export default FlightPlanDetailContainer;

44
src/containers/basis/flight/plan/FlightPlanPilotContainer.js

@ -0,0 +1,44 @@
import React, {useEffect, useState} from 'react';
import {useDispatch, useSelector} from 'react-redux';
import * as Actions from '../../../../modules/basis/flight/actions/basisFlightAction';
import FlightPlanPilot from '../../../../components/basis/flight/plan/FlightPlanPilot';
const FlightPlanPilotContainer = ({handleModal, type}) => {
const dispatch = useDispatch();
const { pilotList, selectGroup } = useSelector(state => state.flightState);
/* 조종사 조회 */
const handleSearch = () => {
const groupId = sessionStorage.getItem('groupId');
if(groupId) {
dispatch(Actions.FLIGHT_PLAN_PILOT_LIST.request(groupId));
}
}
/* 조종사 선택 */
const handleSelectPilot = (cstmrSno) => {
handleModal({target: 'poilot', isOpen: false});
const pilot = pilotList.find(pilot => {
return pilot.cstmrSno === cstmrSno;
});
/* 파일럿 정보 Redux 저장 */
dispatch(Actions.PILOT_SELECT(pilot));
}
useEffect(() => {
handleSearch();
}, [])
return (
<FlightPlanPilot
pilotList = {pilotList}
handleSelectPilot={handleSelectPilot}
/>
)
}
export default FlightPlanPilotContainer;

210
src/modules/basis/flight/actions/basisFlightAction.ts

@ -1,33 +1,197 @@
import { AxiosError } from 'axios';
import { createAsyncAction, ActionType} from 'typesafe-actions';
import { FlightAreaData, FlightPlanArea } from '../models/basisFlightModel';
import { createAsyncAction, ActionType, createAction } from 'typesafe-actions';
import {
PublicAreaData,
FlightPlanArcrftData,
FlightPlanArcrftDataList,
FlightPlanAreaDataList,
// FlightPlanArea,
FlightPlanData,
FlightPlanListRqData, FlightPlanPilotDataList, PilotSelectData, SelectGroupData
} from '../models/basisFlightModel';
// 공역 조회
const AREA_LIST_REQUEST = 'basis/flight/area/LIST_REQUEST';
const AREA_LIST_SUCCESS = 'basis/flight/area/LIST_SUCCESS';
const AREA_LIST_FAILURE = 'basis/flight/area/LIST_FAILURE';
const PUBLIC_AREA_LIST_REQUEST = 'basis/flight/public_area/LIST_REQUEST';
const PUBLIC_AREA_LIST_SUCCESS = 'basis/flight/public_area/LIST_SUCCESS';
const PUBLIC_AREA_LIST_FAILURE = 'basis/flight/public_area/LIST_FAILURE';
// 비행 구역 설정
const FLIGHT_PLAN_AREA_REQUEST = 'basis/flight/plan/area/LIST_REQUEST';
const FLIGHT_PLAN_AREA_SUCCESS = 'basis/flight/plan/area/LIST_SUCCESS';
const FLIGHT_PLAN_AREA_FAILURE = 'basis/flight/plan/area/LIST_FAILURE';
export const AREA_LIST = createAsyncAction(
AREA_LIST_REQUEST,
AREA_LIST_SUCCESS,
AREA_LIST_FAILURE
)<FlightAreaData, { data: FlightAreaData }, AxiosError>();
export const FLIGHT_PLAN_AREA = createAsyncAction(
FLIGHT_PLAN_AREA_REQUEST,
FLIGHT_PLAN_AREA_SUCCESS,
FLIGHT_PLAN_AREA_FAILURE
)<FlightPlanArea, { data: FlightPlanArea }, AxiosError>();
// const FLIGHT_PLAN_AREA_REQUEST = 'basis/flight/plan/area/LIST_REQUEST';
// const FLIGHT_PLAN_AREA_SUCCESS = 'basis/flight/plan/area/LIST_SUCCESS';
// const FLIGHT_PLAN_AREA_FAILURE = 'basis/flight/plan/area/LIST_FAILURE';
// 목록
const FLIGHT_PLAN_LIST_REQUEST = 'basis/flight/plan/list/LIST_REQUEST';
const FLIGHT_PLAN_LIST_SUCCESS = 'basis/flight/plan/list/LIST_SUCCESS';
const FLIGHT_PLAN_LIST_FAILURE = 'basis/flight/plan/list/LIST_FAILURE';
// 상세
const FLIGHT_PLAN_DETAIL_REQUEST = 'basis/flight/plan/detail/DETAIL_REQUEST';
const FLIGHT_PLAN_DETAIL_SUCCESS = 'basis/flight/plan/detail/DETAIL_SUCCESS';
const FLIGHT_PLAN_DETAIL_FAILURE = 'basis/flight/plan/detail/DETAIL_FAILURE';
// 상세 초기화
const FLIGHT_PLAN_DETAIL_INITIAL = 'basis/flight/plan/detail/DETAIL_INIT';
// 생성
const FLIGHT_PLAN_CREATE_REQUEST = 'basis/flight/plan/create/CREATE_REQUEST';
const FLIGHT_PLAN_CREATE_SUCCESS = 'basis/flight/plan/create/CREATE_SUCCESS';
const FLIGHT_PLAN_CREATE_FAILURE = 'basis/flight/plan/create/CREATE_FAILURE';
// 수정
const FLIGHT_PLAN_UPDATE_REQUEST = 'basis/flight/plan/update/UPDATE_REQUEST';
const FLIGHT_PLAN_UPDATE_SUCCESS = 'basis/flight/plan/update/UPDATE_SUCCESS';
const FLIGHT_PLAN_UPDATE_FAILURE = 'basis/flight/plan/update/UPDATE_FAILURE';
// 삭제
const FLIGHT_PLAN_DELETE_REQUEST = 'basis/flight/plan/delete/DELETE_REQUEST';
const FLIGHT_PLAN_DELETE_SUCCESS = 'basis/flight/plan/delete/DELETE_SUCCESS';
const FLIGHT_PLAN_DELETE_FAILURE = 'basis/flight/plan/delete/DELETE_FAILURE';
// 조종사 조회
const FLIGHT_PLAN_PILOT_LIST_REQUEST = 'basis/flight/plan/pilot_list/PILOT_LIST_REQUEST';
const FLIGHT_PLAN_PILOT_LIST_SUCCESS = 'basis/flight/plan/pilot_list/PILOT_LIST_SUCCESS';
const FLIGHT_PLAN_PILOT_LIST_FAILURE = 'basis/flight/plan/pilot_list/PILOT_LIST_FAILURE';
// 조종사 선택
const FLIGHT_PLAN_PILOT_SELECT = 'basis/flight/plan/pilot_list/PILOT_SELECT';
// 기체 조회
const FLIGHT_PLAN_ARCRFT_LIST_REQUEST = 'basis/flight/plan/arcrft_list/ARCRFT_LIST_REQUEST';
const FLIGHT_PLAN_ARCRFT_LIST_SUCCESS = 'basis/flight/plan/arcrft_list/ARCRFT_LIST_SUCCESS';
const FLIGHT_PLAN_ARCRFT_LIST_FAILURE = 'basis/flight/plan/arcrft_list/ARCRFT_LIST_FAILURE';
// 기체 선택
const FLIGHT_PLAN_ARCRFT_SELECT = 'basis/flight/plan/arcrft_list/ARCRFT_SELECT';
// 조종사, 기체 선택 초기화
const PILOT_ARCRFT_SELECT_INITIAL = 'basis/flight/plan/detail/SELECT_INIT';
// 비행 구역 좌표 저장
const AREA_COORDINATE_LIST = 'basis/flight/plan/area/COORDINATE_LIST';
// 비행 구역 상세 저장
const AREA_DETAIL_LIST = 'basis/flight/plan/area/DETAIL_LIST';
// 비행계획서 그룹 선택
const ROUP_SELECT = 'basis/flight/plan/group/select';
// 조종사, 기체 선택 초기화
const AREA_DETAIL_INITIAL = 'basis/flight/plan/detail/AREA_DETAIL_INIT';
// 버퍼 좌표 가져오기
const AREA_BUFFER_LIST_REQUEST = 'basis/flight/plan/area/BUFFER_LIST_REQUEST';
const AREA_BUFFER_LIST_SUCCESS = 'basis/flight/plan/area/BUFFER_LIST_SUCCESS';
const AREA_BUFFER_LIST_FAILURE = 'basis/flight/plan/area/BUFFER_LIST_FAILURE';
export const PUBLIC_AREA_LIST = createAsyncAction(
PUBLIC_AREA_LIST_REQUEST,
PUBLIC_AREA_LIST_SUCCESS,
PUBLIC_AREA_LIST_FAILURE
)<PublicAreaData, { data: PublicAreaData }, AxiosError>();
// export const FLIGHT_PLAN_AREA = createAsyncAction(
// FLIGHT_PLAN_AREA_REQUEST,
// FLIGHT_PLAN_AREA_SUCCESS,
// FLIGHT_PLAN_AREA_FAILURE
// )<FlightPlanArea, { data: FlightPlanArea }, AxiosError>();
// 목록
export const FLIGHT_PLAN_LIST = createAsyncAction(
FLIGHT_PLAN_LIST_REQUEST,
FLIGHT_PLAN_LIST_SUCCESS,
FLIGHT_PLAN_LIST_FAILURE
)<FlightPlanListRqData, [FlightPlanData], AxiosError>();
// 상세
export const FLIGHT_PLAN_DETAIL = createAsyncAction(
FLIGHT_PLAN_DETAIL_REQUEST,
FLIGHT_PLAN_DETAIL_SUCCESS,
FLIGHT_PLAN_DETAIL_FAILURE
)<number, FlightPlanData, AxiosError>();
// 상세 초기화
export const FLIGHT_PLAN_DETAIL_INIT = createAction(FLIGHT_PLAN_DETAIL_INITIAL)();
// 생성
export const FLIGHT_PLAN_CREATE = createAsyncAction(
FLIGHT_PLAN_CREATE_REQUEST,
FLIGHT_PLAN_CREATE_SUCCESS,
FLIGHT_PLAN_CREATE_FAILURE
)<FlightPlanData, string, AxiosError>();
// 수정
export const FLIGHT_PLAN_UPDATE = createAsyncAction(
FLIGHT_PLAN_UPDATE_REQUEST,
FLIGHT_PLAN_UPDATE_SUCCESS,
FLIGHT_PLAN_UPDATE_FAILURE
)<FlightPlanData, string, AxiosError>();
// 삭제
export const FLIGHT_PLAN_DELETE = createAsyncAction(
FLIGHT_PLAN_DELETE_REQUEST,
FLIGHT_PLAN_DELETE_SUCCESS,
FLIGHT_PLAN_DELETE_FAILURE
)<number, string, AxiosError>();
// 조종사 목록
export const FLIGHT_PLAN_PILOT_LIST = createAsyncAction(
FLIGHT_PLAN_PILOT_LIST_REQUEST,
FLIGHT_PLAN_PILOT_LIST_SUCCESS,
FLIGHT_PLAN_PILOT_LIST_FAILURE
)<string, FlightPlanPilotDataList, AxiosError>();
// 조종사 선택
export const PILOT_SELECT = createAction(FLIGHT_PLAN_PILOT_SELECT)<PilotSelectData>();
// 기체 목록
export const FLIGHT_PLAN_ARCRFT_LIST = createAsyncAction(
FLIGHT_PLAN_ARCRFT_LIST_REQUEST,
FLIGHT_PLAN_ARCRFT_LIST_SUCCESS,
FLIGHT_PLAN_ARCRFT_LIST_FAILURE
)<string, FlightPlanArcrftDataList, AxiosError>();
// 조종사 선택
export const ARCRFT_SELECT = createAction(FLIGHT_PLAN_ARCRFT_SELECT)<FlightPlanArcrftData>();
// 조종사, 기체 선택 초기화
export const PILOT_ARCRFT_SELECT_INIT = createAction(PILOT_ARCRFT_SELECT_INITIAL)();
// 비행 구역 좌표 저장 (스텝2 데이터 공유)
export const AREA_COORDINATE_LIST_SAVE = createAction(AREA_COORDINATE_LIST)<FlightPlanAreaDataList>();
// 비행 구역 상세 저장
export const AREA_DETAIL_LIST_SAVE = createAction(AREA_DETAIL_LIST)<FlightPlanAreaDataList>();
// 비행 계획서 그룹 선택
export const FLIGHT_PLAN_GROUP_SELECT = createAction(ROUP_SELECT)<SelectGroupData>();
// 비행 구역 상세 값 초기화
export const AREA_DETAIL_INIT = createAction(AREA_DETAIL_INITIAL)();
// 버퍼 좌표 가져오기
export const FLIGHT_PLAN_AREA_BUFFER_LIST = createAsyncAction(
AREA_BUFFER_LIST_REQUEST,
AREA_BUFFER_LIST_SUCCESS,
AREA_BUFFER_LIST_FAILURE
)<FlightPlanAreaDataList, FlightPlanAreaDataList, AxiosError>();
const actions = {
AREA_LIST,
FLIGHT_PLAN_AREA
PUBLIC_AREA_LIST,
// FLIGHT_PLAN_AREA,
FLIGHT_PLAN_LIST,
FLIGHT_PLAN_DETAIL,
FLIGHT_PLAN_DETAIL_INIT,
FLIGHT_PLAN_CREATE,
FLIGHT_PLAN_UPDATE,
FLIGHT_PLAN_DELETE,
FLIGHT_PLAN_PILOT_LIST,
FLIGHT_PLAN_ARCRFT_LIST,
PILOT_SELECT,
ARCRFT_SELECT,
PILOT_ARCRFT_SELECT_INIT,
AREA_COORDINATE_LIST_SAVE,
AREA_DETAIL_LIST_SAVE,
FLIGHT_PLAN_GROUP_SELECT,
FLIGHT_PLAN_AREA_BUFFER_LIST,
AREA_DETAIL_INIT
};
export type FlightAction = ActionType<typeof actions>;
export type FlightAction = ActionType<typeof actions>;

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

@ -1,9 +1,63 @@
import axios from '../../../utils/customAxiosUtil';
import qs from 'qs';
import { FlightPlanAreaData, FlightPlanAreaDataList, FlightPlanData, FlightPlanListRqData } from '../models/basisFlightModel';
export const flightPlanAPI = {
area: async () => {
return await axios.get(`api/bas/flight/area`);
}
}
area: async () => {
const res = await axios.get(`api/bas/flight/area`);
return res;
},
list: async (data: FlightPlanListRqData) => {
const queryString = qs.stringify(data, {
addQueryPrefix: true,
arrayFormat: 'repeat'
});
const res = await axios.get(`api/bas/flight/plan/list${queryString}`);
return res;
},
detail: async (planSno: number) => {
const res = await axios.get(`api/bas/flight/plan/detail/${planSno}`);
return res;
},
create: async (data: FlightPlanData) => {
console.log('>>> rq : ', data)
const res = await axios.post(`api/bas/flight/plan/create`, data);
console.log('>>> rs : ', res);
return res;
},
update: async (data: FlightPlanData) => {
console.log('>>> rq : ', data)
const res = await axios.put(`api/bas/flight/plan/update`, data);
console.log('>>> rs : ', res);
return res;
},
delete: async (planSno: number) => {
console.log('>>> rq : ', planSno)
const res = await axios.get(`api/bas/flight/plan/delete/${planSno}`);
console.log('>>> rs : ', res);
return res;
},
listPilot: async (groupId: string) => {
console.log('>>> rq : ', groupId)
const res = await axios.get(`api/bas/flight/plan/pilot/${groupId}`);
console.log('>>> rs : ', res);
return res;
},
listArcrft: async (groupId: string) => {
console.log('>>> rq : ', groupId)
const res = await axios.get(`api/bas/flight/plan/arcrft/${groupId}`);
console.log('>>> rs : ', res);
return res;
},
listBuffer: async (data: FlightPlanAreaDataList) => {
console.log('>>> rq : ', data)
const queryString = qs.stringify(data, {
addQueryPrefix: true,
arrayFormat: 'brackets'
});
const res = await axios.post(`api/bas/flight/plan/area/buffer`, data);
console.log('>>> rs : ', res);
return res;
}
}

472
src/modules/basis/flight/models/basisFlightModel.ts

@ -1,21 +1,471 @@
import moment from "moment";
export interface FlightState {
areaList: FlightAreaData | undefined
flightPlanArea: FlightPlanArea | undefined
publicAreaList: PublicAreaData | undefined
flightPlanArea: FlightPlanArea | undefined
list: [FlightPlanData] | undefined
detail: FlightPlanData | undefined
pilotList: FlightPlanPilotDataList | undefined
arcrftList: FlightPlanArcrftDataList | undefined
pilotSelect: PilotSelectData | undefined
arcrftSelect: FlightPlanArcrftData | undefined
areaCoordList: FlightPlanAreaData[] | undefined
areaList: FlightPlanAreaData[] | undefined
selectGroup: SelectGroupData | undefined
}
export interface SelectGroupData {
cstmrSno: number,
groupId: string,
groupNm: string,
}
export interface FlightAreaData {
areaList: []
export interface PublicAreaData {
publicAreaList: []
}
export interface FlightPlanArea {
address : '',
coordinates : '',
redius : '',
altitude_m : '',
altitude_ft : '',
address: string,
coordinates: string,
redius: string,
altitude_m: string,
altitude_ft: string,
}
export interface FlightPlanData {
planSno?: number,
groupId: string,
cstmrSno: number,
memberName: string,
email: string,
hpno: string,
clncd: string,
addr: string,
addrDtlCn: string,
zip: string,
schFltStDt: string,
schFltEndDt: string,
fltPurpose: string,
aprvlYn: string,
delYn: string,
createUserId: string,
createDt: string,
updateUserId: string,
updateDt: string,
areaList?: FlightPlanAreaDataList | undefined,
pilotList?: FlightPlanPilotDataList | undefined,
arcrftList?: FlightPlanArcrftDataList | undefined
// docState: string
}
export interface FlightPlanAreaData {
planAreaSno?: number,
planSno: number,
areaType: string,
fltMethod: string,
bufferZone: number,
fltElev: string,
createUserId?: string,
createDt?: string,
updateUserId?: string,
updateDt?: string,
coordList?: FlightPlanAreaCoordDataList | undefined
bufferCoordList?: FlightPlanAreaCoordDataList | undefined
// docState: string,
}
export interface FlightPlanAreaDataList extends Array<FlightPlanAreaData> {};
export interface FlightPlanAreaCoordData {
planAreaCoordSno?: number,
planAreaSno?: number,
lat: number,
lon: number,
createUserId?: string,
createDt?: string
// docState: string
}
export interface FlightPlanAreaCoordDataList extends Array<FlightPlanAreaCoordData> {};
export interface FlightPlanPilotData {
planPilotSno?: number,
planSno?: number,
cstmrSno?: number,
groupNm: string,
memberName: string,
email: string,
hpno: string,
clncd: string,
addr: string,
addrDtlCn: string,
zip: string,
qlfcNo: string,
carrer: string,
createUserId: string,
createDt: string,
updateUserId: string,
updateDt: string
// docState: string
}
export interface FlightPlanPilotDataList extends Array<FlightPlanPilotData> {};
export interface FlightPlanArcrftData {
planArcrftSno: number,
planSno: number,
arcrftSno: number,
idntfNum: string,
groupNm: string,
prdctNum: string,
arcrftTypeCd: string,
arcrftModelNm: string,
prdctCmpnNm: string,
prdctDate: string,
arcrftLngth: number,
arcrftWdth: number,
arcrftHght: number,
arcrftWght: number,
wghtTypeCd: string,
imageUrl: string,
takeoffWght: number,
useYn: string,
cameraYn: string,
insrncYn: string,
ownerNm: string,
createUserId: string,
createDt: string,
updateUserId: string,
updateDt: string
// docState: string
}
export interface FlightPlanArcrftDataList extends Array<FlightPlanArcrftData> {};
// rq
export interface FlightPlanListRqData {
groupId: string,
cstmrSno: number,
schFltStDt: string,
schFltEndDt: string,
aprvlYn: string
}
export interface FlightPlanAprovRqData {
planSnoList: [number],
aprvlYn: string
}
export interface PilotSelectData {
groupNm: string,
cstmrSno: string,
memberName: string,
email: string,
hpno: string,
clncd: string,
addr: string,
addrDtlCn: string,
zip: string
}
export const initFlight = {
selectGroup: {
cstmrSno: 0,
groupId: '',
groupNm: ''
},
publicAreaList: undefined,
flightPlanArea: undefined,
list: undefined,
detail: {
planSno: 0,
groupId: '',
cstmrSno: 0,
memberName: '',
email: '',
hpno: '',
clncd: '+81',
addr: '',
addrDtlCn: '',
zip: '',
schFltStDt: moment().set({'h': 0, 'm': 0, 's': 0}).format('YYYY-MM-DD HH:mm:ss'),
schFltEndDt: moment().set({'h': 0, 'm': 0, 's': 0}).format('YYYY-MM-DD HH:mm:ss'),
fltPurpose: '',
aprvlYn: '',
delYn: '',
createUserId: '',
createDt: '',
updateUserId: '',
updateDt: '',
areaList: [{
planAreaSno: 0,
planSno: 0,
areaType: '',
fltMethod: '',
bufferZone: 0,
fltElev: '',
createUserId: '',
createDt: '',
updateUserId: '',
updateDt: '',
coordList: [{
planAreaCoordSno: 0,
planAreaSno: 0,
lat: 0,
lon: 0,
createUserId: '',
createDt: ''
}],
bufferCoordList: [{
planAreaCoordSno: 0,
planAreaSno: 0,
lat: 0,
lon: 0,
createUserId: '',
createDt: ''
}],
}],
pilotList: [{
planPilotSno: 0,
planSno: 0,
cstmrSno: 0,
groupNm: '',
memberName: '',
email: '',
hpno: '',
clncd: '+81',
addr: '',
addrDtlCn: '',
zip: '',
qlfcNo: '',
carrer: '',
createUserId: '',
createDt: '',
updateUserId: '',
updateDt: ''
}],
arcrftList: [{
planArcrftSno: 0,
planSno: 0,
arcrftSno: 0,
idntfNum: '',
groupNm: '',
prdctNum: '',
arcrftTypeCd: '',
arcrftModelNm: '',
prdctCmpnNm: '',
prdctDate: '',
arcrftLngth: 0,
arcrftWdth: 0,
arcrftHght: 0,
arcrftWght: 0,
wghtTypeCd: '',
imageUrl: '',
takeoffWght: 0,
useYn: '',
cameraYn: '',
insrncYn: '',
ownerNm: '',
createUserId: '',
createDt: '',
updateUserId: '',
updateDt: ''
}]
},
pilotList: undefined,
arcrftList: undefined,
pilotSelect: undefined,
arcrftSelect: undefined,
areaCoordList: undefined,
areaList: undefined,
};
export const initFlightBas = {
plan: {
planSno: 0,
groupId: '',
cstmrSno: 0,
memberName: '',
email: '',
hpno: '',
clncd: '+81',
addr: '',
addrDtlCn: '',
zip: '',
schFltStDt: moment().set({'h': 0, 'm': 0, 's': 0}).format('YYYY-MM-DD HH:mm:ss'),
schFltEndDt: moment().set({'h': 0, 'm': 0, 's': 0}).format('YYYY-MM-DD HH:mm:ss'),
fltPurpose: '',
aprvlYn: '',
delYn: '',
createUserId: '',
createDt: '',
updateUserId: '',
updateDt: '',
areaList: undefined,
flightPlanArea: undefined
};
pilotList: undefined,
arcrftList: undefined,
},
pilot: {
planPilotSno: 0,
planSno: 0,
cstmrSno: 0,
groupNm: '',
memberName: '',
email: '',
hpno: '',
clncd: '+81',
addr: '',
addrDtlCn: '',
zip: '',
qlfcNo: '',
carrer: '',
createUserId: '',
createDt: '',
updateUserId: '',
updateDt: ''
},
arcrft: {
planArcrftSno: 0,
planSno: 0,
arcrftSno: 0,
idntfNum: '',
groupNm: '',
prdctNum: '',
arcrftTypeCd: '',
arcrftModelNm: '',
prdctCmpnNm: '',
prdctDate: '',
arcrftLngth: 0,
arcrftWdth: 0,
arcrftHght: 0,
arcrftWght: 0,
wghtTypeCd: '',
imageUrl: '',
takeoffWght: 0,
useYn: '',
cameraYn: '',
insrncYn: '',
ownerNm: '',
createUserId: '',
createDt: '',
updateUserId: '',
updateDt: ''
},
area: {
planAreaSno: 0,
planSno: 0,
areaType: '',
fltMethod: '',
bufferZone: 0,
fltElev: '',
createUserId: '',
createDt: '',
updateUserId: '',
updateDt: '',
coordList: undefined
},
coord: {
planAreaCoordSno: 0,
planAreaSno: 0,
lat: 0,
lon: 0,
createUserId: '',
createDt: ''
},
initDetail: {
planSno: 0,
groupId: '',
cstmrSno: 0,
memberName: '',
email: '',
hpno: '',
clncd: '+81',
addr: '',
addrDtlCn: '',
zip: '',
schFltStDt: moment().set({'h': 0, 'm': 0, 's': 0}).format('YYYY-MM-DD HH:mm:ss'),
schFltEndDt: moment().set({'h': 0, 'm': 0, 's': 0}).format('YYYY-MM-DD HH:mm:ss'),
fltPurpose: '',
aprvlYn: '',
delYn: '',
createUserId: '',
createDt: '',
updateUserId: '',
updateDt: '',
areaList: [{
planAreaSno: 0,
planSno: 0,
areaType: '',
fltMethod: '',
bufferZone: 0,
fltElev: '',
createUserId: '',
createDt: '',
updateUserId: '',
updateDt: '',
coordList: [{
planAreaCoordSno: 0,
planAreaSno: 0,
lat: 0,
lon: 0,
createUserId: '',
createDt: ''
}],
bufferCoordList: [{
planAreaCoordSno: 0,
planAreaSno: 0,
lat: 0,
lon: 0,
createUserId: '',
createDt: ''
}],
}],
pilotList: [{
planPilotSno: 0,
planSno: 0,
cstmrSno: 0,
groupNm: '',
memberName: '',
email: '',
hpno: '',
clncd: '+81',
addr: '',
addrDtlCn: '',
zip: '',
qlfcNo: '',
carrer: '',
createUserId: '',
createDt: '',
updateUserId: '',
updateDt: ''
}],
arcrftList: [{
planArcrftSno: 0,
planSno: 0,
arcrftSno: 0,
idntfNum: '',
groupNm: '',
prdctNum: '',
arcrftTypeCd: '',
arcrftModelNm: '',
prdctCmpnNm: '',
prdctDate: '',
arcrftLngth: 0,
arcrftWdth: 0,
arcrftHght: 0,
arcrftWght: 0,
wghtTypeCd: '',
imageUrl: '',
takeoffWght: 0,
useYn: '',
cameraYn: '',
insrncYn: '',
ownerNm: '',
createUserId: '',
createDt: '',
updateUserId: '',
updateDt: ''
}]
}
}

114
src/modules/basis/flight/reducers/basisFlightReducer.ts

@ -2,20 +2,112 @@ import { createReducer } from 'typesafe-actions';
import produce from 'immer';
import * as Actions from '../actions/basisFlightAction';
import { FlightState, initFlight } from '../models/basisFlightModel';
import { FlightState, initFlight, initFlightBas } from '../models/basisFlightModel';
import { any } from 'prop-types';
export const flightReducer = createReducer<FlightState, Actions.FlightAction> ( initFlight )
.handleAction(Actions.AREA_LIST.success, (state, action) =>
export const flightReducer = createReducer<FlightState, Actions.FlightAction>(initFlight)
.handleAction(Actions.PUBLIC_AREA_LIST.success, (state, action) =>
produce(state, draft => {
const {data} = action.payload;
draft.areaList = data;
const { data } = action.payload;
draft.publicAreaList = data;
})
)
.handleAction(Actions.FLIGHT_PLAN_AREA.request, (state, action) =>
produce(state, draft => {
const data = action.payload;
draft.flightPlanArea = data;
)
// .handleAction(Actions.FLIGHT_PLAN_AREA.request, (state, action) =>
// produce(state, draft => {
// const data = action.payload;
// draft.flightPlanArea = data;
// })
// )
// 목록
.handleAction(Actions.FLIGHT_PLAN_LIST.success, (state, action) =>
produce(state, draft => {
const data = action.payload;
draft.list = data;
})
)
// 상세
.handleAction(Actions.FLIGHT_PLAN_DETAIL.success, (state, action) =>
produce(state, draft => {
const data = action.payload;
draft.detail = data;
})
)
.handleAction(Actions.FLIGHT_PLAN_DETAIL_INIT, (state, action) =>
produce(state, draft => {
draft.detail = initFlightBas.initDetail
})
)
// 조종사 조회
.handleAction(Actions.FLIGHT_PLAN_PILOT_LIST.success, (state, action) =>
produce(state, draft => {
const data = action.payload;
draft.pilotList = data;
})
)
// 조종사 선택
.handleAction(Actions.PILOT_SELECT, (state, action) =>
produce(state, draft => {
const data = action.payload;
draft.pilotSelect = data;
})
)
// 기체 조회
.handleAction(Actions.FLIGHT_PLAN_ARCRFT_LIST.success, (state, action) =>
produce(state, draft => {
const data = action.payload;
draft.arcrftList = data;
})
)
// 기체 선택
.handleAction(Actions.ARCRFT_SELECT, (state, action) =>
produce(state, draft => {
const data = action.payload;
draft.arcrftSelect = data;
})
)
// 조종사, 기체 선택 초기화
.handleAction(Actions.PILOT_ARCRFT_SELECT_INIT, (state, action) =>
produce(state, draft => {
draft.arcrftSelect = undefined;
draft.pilotSelect = undefined;
// draft.areaList = undefined;
// draft.areaCoordList = undefined;
})
)
// 비행 구역 좌표 저장
.handleAction(Actions.AREA_COORDINATE_LIST_SAVE, (state, action) =>
produce(state, draft => {
const data = action.payload;
draft.areaCoordList = data;
})
)
// 비행 구역 상세 저장
.handleAction(Actions.AREA_DETAIL_LIST_SAVE, (state, action) =>
produce(state, draft => {
const data = action.payload;
draft.areaList = data;
draft.areaCoordList = data;
})
)
// 비행 계획서 그룹 선택
.handleAction(Actions.FLIGHT_PLAN_GROUP_SELECT, (state, action) =>
produce(state, draft => {
const data = action.payload;
draft.selectGroup = data;
})
)
// 비행 계획서 버퍼 영역 조회
.handleAction(Actions.FLIGHT_PLAN_AREA_BUFFER_LIST.success, (state, action) =>
produce(state, draft => {
const data = action.payload;
draft.areaCoordList = data;
})
)
// 조종사, 기체 선택 초기화
.handleAction(Actions.AREA_DETAIL_INIT, (state, action) =>
produce(state, draft => {
draft.areaList = undefined;
draft.areaCoordList = undefined;
})
)
)

337
src/modules/basis/flight/sagas/basisFlightSaga.ts

@ -9,53 +9,320 @@ import {
import * as MessageActions from '../../../comn/message/actions/comnMessageAction';
import * as Actions from '../actions/basisFlightAction';
import * as Apis from '../apis/basisFlightApi';
import { FlightPlanData } from "../models/basisFlightModel";
import {
FLIGHT_PLAN_ARCRFT_LIST,
FLIGHT_PLAN_CREATE, FLIGHT_PLAN_DELETE,
FLIGHT_PLAN_DETAIL,
FLIGHT_PLAN_PILOT_LIST, FLIGHT_PLAN_UPDATE
} from "../actions/basisFlightAction";
function* listAreaSaga(action: ActionType<typeof Actions.PUBLIC_AREA_LIST.request>) {
try {
const response = yield call(Apis.flightPlanAPI.area);
if (response.errorCode) {
yield put(
MessageActions.IS_ERROR({
errorCode: response.errorCode,
errorMessage: response.errorMessage,
isHistoryBack: false,
isRefresh: false
})
);
return;
}
yield put(
Actions.PUBLIC_AREA_LIST.success({
data: response
})
);
} catch (error: any) {
yield put(
Actions.PUBLIC_AREA_LIST.failure(error)
);
}
}
// function* createFlightPlanArea(action: ActionType<typeof Actions.FLIGHT_PLAN_AREA.request>) {
// try {
// const data = action.payload;
//
// yield put(
// Actions.FLIGHT_PLAN_AREA.success({
// data: data
// })
// )
//
// } catch (error: any) {
// yield put(
// Actions.FLIGHT_PLAN_AREA.failure(error)
// )
// }
// }
// 비행계획서 목록
function* listPlanSaga(action: ActionType<typeof Actions.FLIGHT_PLAN_LIST.request>) {
try {
const data = action.payload;
const response = yield call(Apis.flightPlanAPI.list, data);
if (response.errorCode) {
yield put(
MessageActions.IS_ERROR({
errorCode: response.errorCode,
errorMessage: response.errorMessage,
isHistoryBack: false,
isRefresh: false
})
);
return;
}
yield put(
Actions.FLIGHT_PLAN_LIST.success(response.data)
);
} catch (error: any) {
yield put(
Actions.FLIGHT_PLAN_LIST.failure(error)
);
}
}
// 비행계획서 상세
function* detailPlanSaga(action: ActionType<typeof Actions.FLIGHT_PLAN_DETAIL.request>) {
try {
const data = action.payload;
const response = yield call(Apis.flightPlanAPI.detail, data);
if (response.errorCode) {
yield put(
MessageActions.IS_ERROR({
errorCode: response.errorCode,
errorMessage: response.errorMessage,
isHistoryBack: false,
isRefresh: false
})
);
return;
}
function* listAreaSaga(action: ActionType<typeof Actions.AREA_LIST.request>) {
try {
const response = yield call(Apis.flightPlanAPI.area);
if(response.errorCode) {
yield put(
MessageActions.IS_ERROR({
errorCode: response.errorCode,
errorMessage: response.errorMessage,
isHistoryBack: false,
isRefresh: false
})
);
return;
}
yield put(
Actions.FLIGHT_PLAN_DETAIL.success(response.data)
);
} catch (error: any) {
yield put(
Actions.FLIGHT_PLAN_DETAIL.failure(error)
);
}
}
// 비행계획서 등록
function* createPlanSaga(action: ActionType<typeof Actions.FLIGHT_PLAN_CREATE.request>) {
try {
const detail = action.payload;
const res = yield call(Apis.flightPlanAPI.create, detail);
const { data } = res;
if (data.result) {
yield put(
MessageActions.IS_MESSAGE({
messageCode: SAVE_MESSAGE.code,
message: SAVE_MESSAGE.message,
isHistoryBack: true,
isRefresh: false
})
);
} else {
if (data.errorCode === 'DT002') {
yield put(
Actions.AREA_LIST.success({
data: response
})
MessageActions.IS_ERROR({
errorCode: DUPLATE_MESSAGE.code,
errorMessage: '제작번호 ' + DUPLATE_MESSAGE.message,
isHistoryBack: false,
isRefresh: false
})
);
} catch (error: any) {
} else {
throw Error;
}
}
} catch (error) {
yield put(
MessageActions.IS_ERROR({
errorCode: ERROR_MESSAGE.code,
errorMessage: ERROR_MESSAGE.message,
isHistoryBack: false,
isRefresh: false
})
);
// yield put(Actions.FLIGHT_PLAN_CREATE.failure(error));
}
}
// 비행계획서 수정
function* updatePlanSaga(action: ActionType<typeof Actions.FLIGHT_PLAN_UPDATE.request>) {
try {
const detail = action.payload;
const res = yield call(Apis.flightPlanAPI.update, detail);
const { data } = res;
if (data.result) {
yield put(
MessageActions.IS_MESSAGE({
messageCode: SAVE_MESSAGE.code,
message: SAVE_MESSAGE.message,
isHistoryBack: true,
isRefresh: false
})
);
} else {
if (data.errorCode === 'DT002') {
yield put(
Actions.AREA_LIST.failure(error)
MessageActions.IS_ERROR({
errorCode: DUPLATE_MESSAGE.code,
errorMessage: '제작번호 ' + DUPLATE_MESSAGE.message,
isHistoryBack: false,
isRefresh: false
})
);
} else {
throw Error;
}
}
} catch (error) {
yield put(
MessageActions.IS_ERROR({
errorCode: ERROR_MESSAGE.code,
errorMessage: ERROR_MESSAGE.message,
isHistoryBack: false,
isRefresh: false
})
);
// yield put(Actions.FLIGHT_PLAN_UPDATE.failure(error));
}
}
// 비행계획서 삭제
function* deletePlanSaga(action: ActionType<typeof Actions.FLIGHT_PLAN_DELETE.request>) {
try {
const id = action.payload;
const res = yield call(Apis.flightPlanAPI.delete, id);
function* createFlightPlanArea(action: ActionType<typeof Actions.FLIGHT_PLAN_AREA.request>) {
try {
const data = action.payload;
const { data } = res;
yield put(
Actions.FLIGHT_PLAN_AREA.success({
data: data
})
)
if (data.result) {
yield put(
MessageActions.IS_MESSAGE({
messageCode: DELETE_MESSAGE.code,
message: DELETE_MESSAGE.message,
isHistoryBack: true,
isRefresh: false
})
);
} else {
throw Error;
}
} catch (error) {
yield put(
MessageActions.IS_ERROR({
errorCode: ERROR_MESSAGE.code,
errorMessage: ERROR_MESSAGE.message,
isHistoryBack: false,
isRefresh: false
})
);
// yield put(Actions.FLIGHT_PLAN_DELETE.failure(error));
}
}
// 조종사 목록
function* listPilotSaga(action: ActionType<typeof Actions.FLIGHT_PLAN_PILOT_LIST.request>) {
try {
const data = action.payload;
const response = yield call(Apis.flightPlanAPI.listPilot, data);
if (response.errorCode) {
yield put(
MessageActions.IS_ERROR({
errorCode: response.errorCode,
errorMessage: response.errorMessage,
isHistoryBack: false,
isRefresh: false
})
);
return;
}
} catch (error: any) {
yield put(
Actions.FLIGHT_PLAN_AREA.failure(error)
)
yield put(
Actions.FLIGHT_PLAN_PILOT_LIST.success(response.data)
);
} catch (error: any) {
yield put(
Actions.FLIGHT_PLAN_PILOT_LIST.failure(error)
);
}
}
// 기체 목록
function* listArcrftSaga(action: ActionType<typeof Actions.FLIGHT_PLAN_ARCRFT_LIST.request>) {
try {
const data = action.payload;
const response = yield call(Apis.flightPlanAPI.listArcrft, data);
if (response.errorCode) {
yield put(
MessageActions.IS_ERROR({
errorCode: response.errorCode,
errorMessage: response.errorMessage,
isHistoryBack: false,
isRefresh: false
})
);
return;
}
yield put(
Actions.FLIGHT_PLAN_ARCRFT_LIST.success(response.data)
);
} catch (error: any) {
yield put(
Actions.FLIGHT_PLAN_ARCRFT_LIST.failure(error)
);
}
}
// get buffer list
function* listBuffer(action: ActionType<typeof Actions.FLIGHT_PLAN_AREA_BUFFER_LIST.request>) {
try {
const data = action.payload;
const response = yield call(Apis.flightPlanAPI.listBuffer, data);
if (response.errorCode) {
yield put(
MessageActions.IS_ERROR({
errorCode: response.errorCode,
errorMessage: response.errorMessage,
isHistoryBack: false,
isRefresh: false
})
);
return;
}
yield put(
Actions.FLIGHT_PLAN_AREA_BUFFER_LIST.success(response.data)
);
} catch (error: any) {
yield put(
Actions.FLIGHT_PLAN_AREA_BUFFER_LIST.failure(error)
);
}
}
export function* flightSaga() {
yield takeEvery(Actions.AREA_LIST.request, listAreaSaga);
yield takeEvery(Actions.FLIGHT_PLAN_AREA.request, createFlightPlanArea);
}
yield takeEvery(Actions.PUBLIC_AREA_LIST.request, listAreaSaga);
// yield takeEvery(Actions.FLIGHT_PLAN_AREA.request, createFlightPlanArea);
yield takeEvery(Actions.FLIGHT_PLAN_LIST.request, listPlanSaga)
yield takeEvery(Actions.FLIGHT_PLAN_DETAIL.request, detailPlanSaga)
yield takeEvery(Actions.FLIGHT_PLAN_CREATE.request, createPlanSaga)
yield takeEvery(Actions.FLIGHT_PLAN_UPDATE.request, updatePlanSaga)
yield takeEvery(Actions.FLIGHT_PLAN_DELETE.request, deletePlanSaga)
yield takeEvery(Actions.FLIGHT_PLAN_PILOT_LIST.request, listPilotSaga)
yield takeEvery(Actions.FLIGHT_PLAN_ARCRFT_LIST.request, listArcrftSaga)
yield takeEvery(Actions.FLIGHT_PLAN_AREA_BUFFER_LIST.request, listBuffer)
}

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

@ -11,9 +11,9 @@ const initialState = {
area0006: true, // 초경량비행장치
sensor: 'dust',
drawType: '',
drawType: null,
drawCheck: false
drawCheck: ''
};
const controlReducerReducer = (state = initialState, action) => {

2
src/router/routes/RouteBasis.js

@ -48,7 +48,7 @@ const RouteBasis = [
component: lazy(() => import('../../views/basis/flight/plan/FlightPlanDetail'))
},
{
path: '/basis/flight/plan/detail/:id',
path: '/basis/flight/plan/detail/:planSno',
component: lazy(() => import('../../views/basis/flight/plan/FlightPlanDetail'))
},
];

Loading…
Cancel
Save