diff --git a/src/components/flight/OperationApprovalsTable.js b/src/components/flight/OperationApprovalsTable.js index 3c7bf6bb..0a9d550c 100644 --- a/src/components/flight/OperationApprovalsTable.js +++ b/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: ( + <> + 재검토
+ 사유 + + ), + 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 && ( + + )}
diff --git a/src/components/flight/OperationCheckBoxModal.js b/src/components/flight/OperationCheckBoxModal.js new file mode 100644 index 00000000..c3b36754 --- /dev/null +++ b/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 ( +
+ +
+ ); + }; + + 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 ? ( + + + + ) : ( +
+ {children} +
+ ); + } + + return {childNode}; + }; + + 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: ( + <> + 신청 +
+ 번호 + + ), + dataIndex: 'applyNo', + align: 'center', + width: '20px' + }, + { + title: ( + <> + 신청
+ 구역 수 + + ), + dataIndex: 'zoneNo', + align: 'center', + width: '20px' + }, + { + title: ( + <> + 행정
+ 구역 1 + + ), + dataIndex: 'addr1', + width: '40px', + align: 'center', + render: addr1 => { + return addr1 ?? '-'; + } + }, + { + title: ( + <> + 행정
+ 구역 2 + + ), + dataIndex: 'addr2', + width: '40px', + align: 'center', + render: addr2 => { + return addr2 ?? '-'; + } + }, + { + title: ( + <> + 상세 +
+ 주소 + + ), + dataIndex: 'addr3', + width: '40px', + align: 'center', + render: addr3 => { + return addr3 ?? '-'; + } + }, + { + title: ( + <> + 장애물 +
+ 제한 표면 + + ), + dataIndex: 'limitZoneNm', + width: '10px', + align: 'center' + }, + { + title: ( + <> + 중심 좌표 +
+ (위도, 경도) + + ), + dataIndex: 'areaList', + align: 'center', + width: '40px', + render: (areaList, record) => ( + <> + {record.lat.toFixed(5)}, +
+ {record.lon.toFixed(5)} + + ) + }, + { + title: ( + <> + 비행 반경 +
+ (m이내) + + ), + dataIndex: 'bufferZone', + align: 'center', + width: '30px' + }, + { + title: ( + <> + 신청 고도 +
+ (m이하) + + ), + dataIndex: 'fltElev', + align: 'center', + width: '30px' + }, + { + title: <>비행 목적, + dataIndex: 'purpose', + align: 'center', + width: '10px', + render: purpose => { + return purpose ?? '-'; + } + }, + { + title: ( + <> + LAANC +
+ 검토 결과 + + ), + dataIndex: 'approvalCd', + align: 'center', + width: '10px', + render: approvalCd => { + return ( + <> + {approvalCd === 'U' + ? '비대상' + : approvalCd === 'S' + ? '승인' + : approvalCd === 'C' + ? '조건부승인' + : '미승인'} + + ); + } + }, + { + title: ( + <> + 관제과 +
+ 검토결과 + + ), + dataIndex: 'reviewedType', + align: 'center', + width: '30px', + render: reviewedType => { + return ( + <> + {reviewedType === 'R' + ? '검토완료' + : reviewedType === 'W' + ? '검토대기' + : reviewedType === 'C' + ? '검토취소' + : '재검토요청'} + + ); + } + }, + { + title: ( + <> + 재검토
+ 사유 + + ), + 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 ( + props.setIsCheckBoxModal(!props.setIsCheckBoxModal)} + className='modal-dialog-centered modal-xl' + > + props.setIsCheckBoxModal(!props.setIsCheckBoxModal)} + > + 재검토 요청 + + +
+ +
+ ({ + ...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} + /> + + + + + + + + + ); +} diff --git a/src/redux/features/laanc/laancThunk.ts b/src/redux/features/laanc/laancThunk.ts index 40bd1c4e..0fca27ac 100644 --- a/src/redux/features/laanc/laancThunk.ts +++ b/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 {