sanguu516
1 month ago
3 changed files with 447 additions and 15 deletions
@ -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> |
||||
); |
||||
} |
Loading…
Reference in new issue