Browse Source

feat/운항과 재검토 요청 작업중

master
sanguu516 1 month ago
parent
commit
a8e5b4ec9d
  1. 66
      src/components/flight/OperationApprovalsTable.js
  2. 375
      src/components/flight/OperationCheckBoxModal.js
  3. 21
      src/redux/features/laanc/laancThunk.ts

66
src/components/flight/OperationApprovalsTable.js

@ -11,6 +11,7 @@ import {
import { ERROR_MESSAGE, ERROR_TITLE } from '@src/configs/msgConst';
import OperationModal from './OperationModal';
import ScrollContainer from 'react-indiana-drag-scroll';
import OperationCheckBoxModal from './OperationCheckBoxModal';
export default function OperationApprovalsTable(props) {
const dispatch = useDispatch();
@ -28,6 +29,9 @@ export default function OperationApprovalsTable(props) {
U: 0
});
// 체크박스 팝업 테이블 데이터
const [checkData, setCheckData] = useState([]);
const scrollContainerRef = useRef(null);
// 확장된 행 키
@ -49,6 +53,9 @@ export default function OperationApprovalsTable(props) {
// 체크박스 선택
const [checkList, setCheckList] = useState([]);
// 체큽작스 모달
const [isCheckBoxModal, setIsCheckBoxModal] = useState(false);
// 수정 키 확인
const isEditing = record => record.key === editingKey;
@ -502,6 +509,19 @@ export default function OperationApprovalsTable(props) {
);
}
},
{
title: (
<>
재검토 <br />
사유
</>
),
dataIndex: 'reviewedReason',
width: '70px',
align: 'center',
render: text => (text ? `${text}` : '-')
},
{
title: '비고',
dataIndex: 'areaList',
@ -723,6 +743,12 @@ export default function OperationApprovalsTable(props) {
: '검토대기';
}
},
{
dataIndex: 'reviewedReason',
width: '70px',
align: 'center',
render: text => (text ? `${text}` : '-')
},
{
title: '비고',
dataIndex: 'planAreaSno',
@ -739,7 +765,7 @@ export default function OperationApprovalsTable(props) {
const data = [];
record.areaList.map((item, index) => {
data.push({
key: `${item.planAreaSno}-${index}`,
key: `${item.planSno}`,
applyNo: item.applyNo,
applyDt: item.applyDt,
zoneNo: item.zoneNo,
@ -764,6 +790,7 @@ export default function OperationApprovalsTable(props) {
addr1: item.addr1,
addr2: item.addr2,
addr3: item.addr3,
reviewedReason: item.reviewedReason,
limitZoneNm: item?.limitZoneNm ? item?.limitZoneNm : '-'
});
});
@ -814,7 +841,10 @@ export default function OperationApprovalsTable(props) {
key.startsWith(`child_${record.planSno}_`)
)
}}
dataSource={data}
dataSource={record.areaList.map((item, index) => ({
...item,
key: `child_${record.planSno}_${item.planAreaSno}`
}))}
pagination={false}
components={{
body: {
@ -1070,7 +1100,7 @@ export default function OperationApprovalsTable(props) {
if (key.startsWith('parent_')) {
const childKeys = record.areaList
.filter(child => child.reviewedType !== 'R')
.filter(child => child.reviewedType === 'R')
.map(child => `child_${record.planSno}_${child.planAreaSno}`);
if (selected) {
@ -1089,7 +1119,7 @@ export default function OperationApprovalsTable(props) {
? laancAprvList.flatMap(parent => {
const parentKey = `parent_${parent.planSno}`;
const selectableChildren = parent.areaList.filter(
child => child.reviewedType !== 'R'
child => child.reviewedType === 'R'
);
const childKeys = selectableChildren.map(
child => `child_${parent.planSno}_${child.planAreaSno}`
@ -1113,7 +1143,7 @@ export default function OperationApprovalsTable(props) {
laancAprvList.forEach(parent => {
const parentKey = `parent_${parent.planSno}`;
const selectableChildren = parent.areaList.filter(
child => child.reviewedType !== 'R'
child => child.reviewedType === 'R'
);
const childKeys = selectableChildren.map(
child => `child_${parent.planSno}_${child.planAreaSno}`
@ -1170,6 +1200,24 @@ export default function OperationApprovalsTable(props) {
false
);
}
const planAreaSnoList = [
...new Set(
checkList
.filter(item => item.startsWith('child_')) // 'child_'로 시작하는 항목 필터링
.map(item => item.split('_').pop()) // 마지막 언더바 이후의 숫자 추출
)
];
// res에서 planAreaSnoList에 해당하는 데이터만 추출 2차원 배열 말고 1차원 배열로 추출
const res = laancAprvList.flatMap(item =>
item.areaList.filter(area =>
planAreaSnoList.includes(area.planAreaSno.toString())
)
);
setCheckData(res);
setIsCheckBoxModal(true);
// try {
// const planAreaSnoList = [
// ...new Set(
@ -1212,6 +1260,14 @@ export default function OperationApprovalsTable(props) {
data={validData}
/>
)}
{isCheckBoxModal && (
<OperationCheckBoxModal
checkData={checkData}
setCheckData={setCheckData}
isCheckBoxModal={isCheckBoxModal}
setIsCheckBoxModal={setIsCheckBoxModal}
/>
)}
<div className='search-download'>
<div>
<span className='search-case'>

375
src/components/flight/OperationCheckBoxModal.js

@ -0,0 +1,375 @@
import {
Button,
Modal,
ModalHeader,
ModalBody,
ModalFooter
} from '@component/ui';
import React, { useEffect, useState, useRef } from 'react';
import { Table, Form, Input } from 'antd';
import ScrollContainer from 'react-indiana-drag-scroll';
export default function OperationCheckBoxModal(props) {
console.log('>>', props.checkData);
const scrollContainerRef = useRef(null);
const [dataSource, setDataSource] = useState(props.checkData);
const EditableRow = ({ index, ...props }) => {
const [form] = Form.useForm();
return (
<Form form={form} component={false}>
<tr {...props} />
</Form>
);
};
const EditableCell = ({
title,
editable,
children,
dataIndex,
record,
handleSave,
...restProps
}) => {
const [editing, setEditing] = useState(false);
const inputRef = useRef(null);
const [form] = Form.useForm();
useEffect(() => {
if (editing) {
inputRef.current?.focus();
}
}, [editing]);
const toggleEdit = () => {
setEditing(!editing);
form.setFieldsValue({ [dataIndex]: record[dataIndex] });
};
const save = async () => {
try {
const values = await form.validateFields();
setEditing(false);
handleSave({ ...record, ...values });
} catch (errInfo) {
console.log('Save failed:', errInfo);
}
};
let childNode = children;
if (editable) {
childNode = editing ? (
<Form.Item
style={{ margin: 0 }}
name={dataIndex}
rules={[{ required: true, message: `${title} is required.` }]}
>
<Input ref={inputRef} onPressEnter={save} onBlur={save} />
</Form.Item>
) : (
<div
className='editable-cell-value-wrap'
style={{ paddingRight: 24 }}
onClick={toggleEdit}
>
{children}
</div>
);
}
return <td {...restProps}>{childNode}</td>;
};
const handleSave = row => {
const newData = [...dataSource];
const index = newData.findIndex(item => row.key === item.key);
const item = newData[index];
newData.splice(index, 1, { ...item, ...row });
setDataSource(newData);
};
const defaultColumns = [
{
title: (
<>
신청
<br />
번호
</>
),
dataIndex: 'applyNo',
align: 'center',
width: '20px'
},
{
title: (
<>
신청 <br />
구역
</>
),
dataIndex: 'zoneNo',
align: 'center',
width: '20px'
},
{
title: (
<>
행정 <br />
구역 1
</>
),
dataIndex: 'addr1',
width: '40px',
align: 'center',
render: addr1 => {
return addr1 ?? '-';
}
},
{
title: (
<>
행정 <br />
구역 2
</>
),
dataIndex: 'addr2',
width: '40px',
align: 'center',
render: addr2 => {
return addr2 ?? '-';
}
},
{
title: (
<>
상세
<br />
주소
</>
),
dataIndex: 'addr3',
width: '40px',
align: 'center',
render: addr3 => {
return addr3 ?? '-';
}
},
{
title: (
<>
장애물
<br />
제한 표면
</>
),
dataIndex: 'limitZoneNm',
width: '10px',
align: 'center'
},
{
title: (
<>
중심 좌표
<br />
(위도, 경도)
</>
),
dataIndex: 'areaList',
align: 'center',
width: '40px',
render: (areaList, record) => (
<>
{record.lat.toFixed(5)},
<br />
{record.lon.toFixed(5)}
</>
)
},
{
title: (
<>
비행 반경
<br />
(m이내)
</>
),
dataIndex: 'bufferZone',
align: 'center',
width: '30px'
},
{
title: (
<>
신청 고도
<br />
(m이하)
</>
),
dataIndex: 'fltElev',
align: 'center',
width: '30px'
},
{
title: <>비행 목적</>,
dataIndex: 'purpose',
align: 'center',
width: '10px',
render: purpose => {
return purpose ?? '-';
}
},
{
title: (
<>
LAANC
<br />
검토 결과
</>
),
dataIndex: 'approvalCd',
align: 'center',
width: '10px',
render: approvalCd => {
return (
<>
{approvalCd === 'U'
? '비대상'
: approvalCd === 'S'
? '승인'
: approvalCd === 'C'
? '조건부승인'
: '미승인'}
</>
);
}
},
{
title: (
<>
관제과
<br />
검토결과
</>
),
dataIndex: 'reviewedType',
align: 'center',
width: '30px',
render: reviewedType => {
return (
<>
{reviewedType === 'R'
? '검토완료'
: reviewedType === 'W'
? '검토대기'
: reviewedType === 'C'
? '검토취소'
: '재검토요청'}
</>
);
}
},
{
title: (
<>
재검토 <br />
사유
</>
),
dataIndex: 'reviewedReason',
width: '110px',
align: 'center',
editable: true,
render: reviewedReason => {
return reviewedReason ?? '재검토 사유를 작성해주세요';
}
}
];
const columns = defaultColumns.map(col => {
if (!col.editable) {
return col;
}
return {
...col,
onCell: record => ({
record,
editable: col.editable,
dataIndex: col.dataIndex,
title: col.title,
handleSave
})
};
});
const components = {
body: {
row: EditableRow,
cell: EditableCell
}
};
return (
<Modal
isOpen={props.isCheckBoxModal}
toggle={() => props.setIsCheckBoxModal(!props.setIsCheckBoxModal)}
className='modal-dialog-centered modal-xl'
>
<ModalHeader
toggle={() => props.setIsCheckBoxModal(!props.setIsCheckBoxModal)}
>
재검토 요청
</ModalHeader>
<ModalBody className='onestop-validation'>
<div className='invoice-list-dataTable flight-approval'>
<ScrollContainer
className='scroll-container'
ref={scrollContainerRef}
hideScrollbars={false}
vertical={true}
horizontal={true}
activationDistance={10}
ignoreElements='.editable-input' // 이 클래스의 요소는 드래그 이벤트에서 제외
>
<div style={{ width: '2000px' }}>
<Table
dataSource={dataSource.map((item, index) => ({
...item,
key: `parent_${item.planSno}`
}))}
components={components}
rowClassName={record => {
let className = '';
if (record.approvalCd === 'S') {
className += 'flight-approval-row';
} else if (record.approvalCd === 'F') {
className += 'flight-not-approval-row';
} else if (record.approvalCd === 'C') {
className += 'flight-condition-approval-row editable-row';
} else className += 'editable-row';
return className;
}}
columns={columns}
scroll={{ x: 1700 }}
pagination={false}
rowHoverable={false}
expandIconColumnIndex={-1}
/>
</div>
</ScrollContainer>
</div>
</ModalBody>
<ModalFooter>
<Button
color='primary'
// onClick={() => props.setIsModal(!props.setIsModal)}
>
확인
</Button>
</ModalFooter>
</Modal>
);
}

21
src/redux/features/laanc/laancThunk.ts

@ -282,16 +282,17 @@ export const getLaancAprvList = createAsyncThunk(
if (item.areaList.length <= 1) {
return {
...item,
fltElev: item.areaList[0].fltElev,
bufferZone: item.areaList[0].bufferZone,
rm: item.areaList[0].rm,
era: item.areaList[0].era,
dtl: item.areaList[0].dtl,
planAreaSno: item.areaList[0].planAreaSno,
reqRadius: item.areaList[0].reqRadius,
reviewedType: item.areaList[0].reviewedType,
allowRadius: item.areaList[0].allowRadius,
fltElevMax: item.areaList[0].fltElevMax
...item.areaList[0]
// fltElev: item.areaList[0].fltElev,
// bufferZone: item.areaList[0].bufferZone,
// rm: item.areaList[0].rm,
// era: item.areaList[0].era,
// dtl: item.areaList[0].dtl,
// planAreaSno: item.areaList[0].planAreaSno,
// reqRadius: item.areaList[0].reqRadius,
// reviewedType: item.areaList[0].reviewedType,
// allowRadius: item.areaList[0].allowRadius,
// fltElevMax: item.areaList[0].fltElevMax,
};
} else {
return {

Loading…
Cancel
Save