diff --git a/src/components/account/login/AccountLogin.js b/src/components/account/login/AccountLogin.js
index 026f88e9..cb1d4530 100644
--- a/src/components/account/login/AccountLogin.js
+++ b/src/components/account/login/AccountLogin.js
@@ -69,7 +69,7 @@ export const AccountLogin = ({ history }) => {
if (meta.requestStatus === 'fulfilled') {
if (loginForm?.userId === 'GMPATC') {
- history.push('/flight/Approvals/new');
+ history.push('/operation/approvals');
} else {
history.push('/control');
}
diff --git a/src/components/flight/NewFlightApprovalsTable.js b/src/components/flight/ControlApprovalsTable.js
similarity index 99%
rename from src/components/flight/NewFlightApprovalsTable.js
rename to src/components/flight/ControlApprovalsTable.js
index 852dd703..6489e81b 100644
--- a/src/components/flight/NewFlightApprovalsTable.js
+++ b/src/components/flight/ControlApprovalsTable.js
@@ -13,7 +13,7 @@ import {
} from '@src/redux/features/laanc/laancThunk';
import { ERROR_MESSAGE, ERROR_TITLE } from '@src/configs/msgConst';
-export default function NewFlightApprovalsTable(props) {
+export default function ControlApprovalsTable(props) {
const dispatch = useDispatch();
// 비행승인 목록
diff --git a/src/components/flight/OperationApprovalsTable.js b/src/components/flight/OperationApprovalsTable.js
new file mode 100644
index 00000000..0bc7452a
--- /dev/null
+++ b/src/components/flight/OperationApprovalsTable.js
@@ -0,0 +1,1149 @@
+import React, { useEffect, useState } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+import { Button, Card } from '@component/ui';
+import { openModal } from '@src/redux/features/comn/message/messageSlice';
+import { FaAngleDown, FaAngleUp } from 'react-icons/fa';
+import { Form, Input, Table, Typography } from 'antd';
+import { HOST } from '../../configs/constants';
+import axios from 'axios';
+import { getAccessToken } from '../../utility/authService/jwtTokenUtil';
+import {
+ updateLaancAprv,
+ getLaancAprvList
+} from '@src/redux/features/laanc/laancThunk';
+import { ERROR_MESSAGE, ERROR_TITLE } from '@src/configs/msgConst';
+
+export default function OperationApprovalsTable(props) {
+ const dispatch = useDispatch();
+
+ // 비행승인 목록
+ const { laancAprvList, laancElev, laancAprvLoading } = useSelector(
+ state => state.laancState
+ );
+
+ // 승인, 미승인, 비대상 건수
+ const [approvalCdValue, setApprovalCdValue] = useState({
+ S: 0,
+ F: 0,
+ C: 0,
+ U: 0
+ });
+
+ // 확장된 행 키
+ const [expandedRowKeys, setExpandedRowKeys] = useState([]);
+
+ // 수정 키
+ const [editingKey, setEditingKey] = useState('');
+
+ // select row key
+ const [selectedRowKey, setSelectedRowKey] = useState('');
+
+ const [form] = Form.useForm();
+
+ // 수정 키 확인
+ const isEditing = record => record.key === editingKey;
+
+ useEffect(() => {
+ let approvalCdValue = { S: 0, F: 0, C: 0, U: 0 };
+
+ laancAprvList.map(item => {
+ item.areaList.map(area => {
+ if (area.approvalCd === 'S') {
+ approvalCdValue.S += 1;
+ } else if (area.approvalCd === 'F') {
+ approvalCdValue.F += 1;
+ } else if (area.approvalCd === 'C') {
+ approvalCdValue.C += 1;
+ } else {
+ approvalCdValue.U += 1;
+ }
+ });
+ });
+
+ setApprovalCdValue({
+ F: approvalCdValue.F,
+ S: approvalCdValue.S,
+ C: approvalCdValue.C,
+ U: approvalCdValue.U
+ });
+
+ if (editingKey) {
+ setEditingKey('');
+ }
+ }, [laancAprvList]);
+
+ // 수정 이벤트
+ const edit = record => {
+ form.setFieldsValue({
+ planAreaSno: record.planAreaSno,
+ bufferZone: record.bufferZone,
+ fltElev: record.fltElev,
+ dtl: record.dtl,
+ era: record.era,
+ rm: record.rm,
+ ...record
+ });
+ setEditingKey(record.key);
+ };
+
+ // 취소 이벤트
+ const cancel = () => {
+ setEditingKey('');
+ };
+
+ // 저장 이벤트
+ const save = async (key, type) => {
+ try {
+ const row = await form.validateFields();
+ const index = { ...row, planAreaSno: selectedRowKey };
+
+ const updateRes = await dispatch(
+ updateLaancAprv([
+ {
+ planAreaSno: selectedRowKey,
+ bufferZone: row.bufferZone,
+ fltElev: row.fltElev,
+ dtl: row.dtl || '',
+ era: row.era || '',
+ rm: row.rm || ''
+ }
+ ])
+ );
+
+ if (updateRes.meta.requestStatus === 'fulfilled') {
+ setEditingKey('');
+ await dispatch(
+ getLaancAprvList({
+ searchStDt: props.startDate,
+ searchEndDt: props.endDate
+ })
+ );
+ } else {
+ handlerErrorModal(ERROR_TITLE, ERROR_MESSAGE);
+ }
+ } catch (errInfo) {
+ handlerErrorModal(ERROR_TITLE, ERROR_MESSAGE);
+ }
+ };
+
+ // 데이터
+ const columns = [
+ {
+ title: (
+ <>
+ 신청
+
+ 번호
+ >
+ ),
+ dataIndex: 'applyNo',
+ align: 'center',
+ width: '60px'
+ },
+ {
+ title: (
+ <>
+ 신청
월
+ >
+ ),
+ dataIndex: 'applyDtMonth',
+ width: '70px',
+ align: 'center',
+ render: text => `${text}월`
+ },
+ {
+ title: (
+ <>
+ 신청
일
+ >
+ ),
+ dataIndex: 'applyDtDay',
+ width: '70px',
+ align: 'center',
+
+ render: text => `${text}일`
+ },
+ {
+ title: (
+ <>
+ 신청
+ 구역 수
+ >
+ ),
+ dataIndex: 'areaList',
+ align: 'center',
+ width: '85px',
+ render: areaList => <>총{areaList.length}건>
+ },
+ {
+ title: <>신청자>,
+ dataIndex: 'applyNm',
+ width: '90px',
+ align: 'center',
+
+ render: text => (text ? text : '-')
+ },
+ {
+ title: (
+ <>
+ 행정
+ 구역 1
+ >
+ ),
+ dataIndex: 'areaList',
+ width: '90px',
+ align: 'center',
+ render: areaList => {
+ return areaList.length <= 1 && areaList[0].addr1
+ ? areaList[0].addr1
+ : '-';
+ }
+ },
+ {
+ title: (
+ <>
+ 행정
+ 구역 2
+ >
+ ),
+ dataIndex: 'areaList',
+ width: '90px',
+ align: 'center',
+ render: areaList => {
+ return areaList.length <= 1 && areaList[0].addr2
+ ? areaList[0].addr2
+ : '-';
+ }
+ },
+ {
+ title: (
+ <>
+ 상세
+ 주소
+ >
+ ),
+ dataIndex: 'areaList',
+ width: '100px',
+ align: 'center',
+ render: areaList => {
+ return areaList.length <= 1 && areaList[0].addr3
+ ? areaList[0].addr3
+ : '-';
+ }
+ },
+ {
+ title: (
+ <>
+ 장애물
+ 제한
+
+ 표면
+
+ >
+ ),
+ dataIndex: 'areaList',
+ width: '100px',
+ align: 'center',
+ render: areaList => {
+ return areaList.length <= 1
+ ? areaList[0].fltElevMax === 120
+ ? '원추'
+ : areaList[0].fltElevMax > 45 && areaList[0].fltElevMax < 100
+ ? '수평'
+ : '-'
+ : '-';
+ }
+ },
+ {
+ title: (
+ <>
+ 증심좌표
+ (위도,경도)
+ >
+ ),
+ dataIndex: 'areaList',
+ align: 'center',
+ width: '85px',
+ render: areaList => {
+ return areaList.length <= 1 ? (
+ <>
+ {areaList[0].lat.toFixed(5)},
+
+ {areaList[0].lon.toFixed(5)}
+ >
+ ) : (
+ '-'
+ );
+ }
+ },
+ {
+ title: (
+ <>
+ 비행
+ 반경
+
+ (m이내)
+ >
+ ),
+ dataIndex: 'bufferZone',
+ align: 'center',
+ width: '80px',
+ editable: true,
+ render: (text, record) => {
+ return text ? text : '-';
+ }
+ },
+ {
+ title: (
+ <>
+ 신청
+ 고도
+
+ (m이하)
+ >
+ ),
+ dataIndex: 'fltElev',
+ align: 'center',
+ width: '80px',
+ editable: true,
+ render: (text, record) => {
+ return text ? text : '-';
+ }
+ },
+ {
+ title: (
+ <>
+ 최고비행
+
+ 해발고도 (m)
+ >
+ ),
+ dataIndex: 'fltElevMax',
+ align: 'center',
+ width: '80px',
+ render: (text, record) => {
+ return text ? text : '-';
+ }
+ },
+ {
+ title: (
+ <>
+ 세부
+ 사항
+ >
+ ),
+ dataIndex: 'dtl',
+ align: 'center',
+ editable: true,
+ width: '110px',
+ render: dtl => {
+ return dtl ? dtl : '-';
+ }
+ },
+ {
+ title: (
+ <>
+ 비행
+ 목적
+ >
+ ),
+ dataIndex: 'areaList',
+ align: 'center',
+ width: '110px',
+ render: areaList => {
+ return areaList.length <= 1 && areaList[0].purpose
+ ? areaList[0].purpose
+ : '-';
+ }
+ },
+ {
+ title: (
+ <>
+ 긴급
+
+ 구조 기관
+ >
+ ),
+ dataIndex: 'era',
+ align: 'center',
+ width: '110px',
+ editable: true,
+ render: era => {
+ return era ? era : '-';
+ }
+ },
+ {
+ title: <>비고>,
+ dataIndex: 'rm',
+ align: 'center',
+ width: '110px',
+ editable: true,
+ render: rm => {
+ return rm ? rm : '-';
+ }
+ },
+ {
+ title: (
+ <>
+ 검토
+ 결과
+ >
+ ),
+ dataIndex: 'areaList',
+ align: 'center',
+ width: '120px',
+ render: areaList => {
+ const approvalCounts = areaList.reduce(
+ (counts, item) => {
+ if (item.approvalCd === 'U') {
+ counts.unapproved += 1;
+ } else if (item.approvalCd === 'S') {
+ counts.approved += 1;
+ } else if (item.approvalCd === 'C') {
+ counts.conditionalapproval += 1;
+ } else {
+ counts.pending += 1;
+ }
+ return counts;
+ },
+ { unapproved: 0, approved: 0, pending: 0, conditionalapproval: 0 }
+ );
+
+ return (
+ <>
+ {areaList.length > 1 ? (
+ <>
+ 승인: {approvalCounts.approved}건
+ 미승인:
+ {approvalCounts.pending}건
+
+ 조건부승인:{approvalCounts.conditionalapproval}건
+ 비대상:
+ {approvalCounts.unapproved}건
+ >
+ ) : (
+ <>
+ {areaList[0].approvalCd === 'U'
+ ? '비대상'
+ : areaList[0].approvalCd === 'S'
+ ? '승인'
+ : areaList[0].approvalCd === 'C'
+ ? '조건부승인'
+ : '미승인'}
+ >
+ )}
+ >
+ );
+ }
+ },
+ {
+ title: <>더보기>,
+ dataIndex: 'areaList',
+ align: 'center',
+ width: '130px',
+ render: (areaList, record) =>
+ areaList.length > 1 ? (
+
+ ) : (
+ <>->
+ )
+ },
+ {
+ title: '편집',
+ dataIndex: 'planAreaSno',
+ align: 'center',
+ width: '110px',
+ render: (_, record) => {
+ const editable = isEditing(record);
+ return record.areaList.length <= 1 ? (
+ editable ? (
+
+
+ {lon.toFixed(5)}
+ >
+ );
+ }
+ },
+ {
+ dataIndex: 'bufferZone',
+ align: 'center',
+ editable: true,
+ width: '80px'
+ },
+ {
+ dataIndex: 'fltElev',
+ align: 'center',
+ editable: true,
+ width: '80px'
+ },
+ {
+ dataIndex: 'fltElevMax',
+ align: 'center',
+ width: '80px',
+ render: text => {
+ return text ? text : <>->;
+ }
+ },
+ {
+ dataIndex: 'dtl',
+ align: 'center',
+ editable: true,
+ width: '110px',
+ render: text => {
+ return text ? text : <>->;
+ }
+ },
+ {
+ dataIndex: 'purpose',
+ align: 'center',
+ width: '110px',
+ render: text => {
+ return text ? text : <>->;
+ }
+ },
+ {
+ dataIndex: 'era',
+ align: 'center',
+ editable: true,
+ width: '110px',
+ render: text => {
+ return text ? text : <>->;
+ }
+ },
+ {
+ dataIndex: 'rm',
+ align: 'center',
+ editable: true,
+ width: '110px',
+ render: text => {
+ return text ? text : <>->;
+ }
+ },
+ {
+ dataIndex: 'approvalCd',
+ align: 'center',
+ width: '120px',
+ render: text => (
+ <>
+ {text === 'U'
+ ? '비대상'
+ : text === 'S'
+ ? '승인'
+ : text === 'C'
+ ? '조건부승인'
+ : '미승인'}
+ >
+ )
+ },
+ {
+ dataIndex: '더보기',
+ align: 'center',
+ width: '130px',
+ render: text => {
+ return <>->;
+ }
+ },
+ {
+ dataIndex: 'planAreaSno',
+ align: 'center',
+ width: '110px',
+ render: (_, record) => {
+ const editable = isEditing(record);
+ return editable ? (
+
+