asb_cloud_front/src/pages/Measure/MeasureTable.jsx

166 lines
6.4 KiB
JavaScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState, useEffect, memo, useMemo, useCallback } from 'react'
import { Button, Form, Input, Popconfirm, Timeline } from 'antd'
import {
CheckSquareOutlined,
EditOutlined,
SaveOutlined,
PlusOutlined,
CloseCircleOutlined,
DeleteOutlined
} from '@ant-design/icons'
import LoaderPortal from '@components/LoaderPortal'
import { invokeWebApiWrapperAsync } from '@components/factory'
import { hasPermission } from '@utils/permissions'
import { formatDate } from '@utils'
import { MeasureService } from '@api'
import { View } from './View'
import '@styles/index.css'
import '@styles/measure.css'
const createEditingColumns = (cols, renderDelegate) =>
cols.map(col => ({ render: renderDelegate, ...col }))
const disabled = !hasPermission('Measure.edit')
export const MeasureTable = memo(({ idWell, group, updateMeasuresFunc, additionalButtons }) => {
const [showLoader, setShowLoader] = useState(false)
const [displayedValues, setDisplayedValues] = useState({})
const [editingColumns, setEditingColumns] = useState(group.columns)
const [isTableEditing, setIsTableEditing] = useState(false)
const [editingActionName, setEditingActionName] = useState('')
const [measuresForm] = Form.useForm()
const data = useMemo(() => group?.values?.length > 0 ? group.values : [group?.defaultValue], [group?.defaultValue, group?.values])
useEffect(() => setDisplayedValues(data.at(-1)), [data])
useEffect(() => {
const switchableColumns = createEditingColumns(
group.columns,
isTableEditing ? () => <Input className={'w-100 measure-input'} /> : null
)
if(editingActionName === 'edit')
measuresForm.setFieldsValue(displayedValues?.data)
else if(editingActionName === 'add')
measuresForm.resetFields()
setEditingColumns(switchableColumns)
}, [isTableEditing, group.columns, editingActionName, displayedValues?.data, measuresForm])
const markMeasuresAsDeleted = async () => await invokeWebApiWrapperAsync(
async () => {
await MeasureService.markAsDelete(idWell, displayedValues.id)
updateMeasuresFunc()
},
setShowLoader,
`Не удалось удалить запись ${displayedValues.id} для скважины "${idWell}"`,
'Удаление записи для скважины'
)
const editingDisabled = useMemo(() => disabled || !!displayedValues?.isDefaultData, [displayedValues?.isDefaultData])
const deleteDisabled = useMemo(() => !hasPermission('Measure.delete') || !!displayedValues?.isDefaultData, [displayedValues?.isDefaultData])
const editTable = useCallback((action) => {
setEditingActionName(action)
setIsTableEditing(true)
}, [])
const handleSubmitMeasuresForm = useCallback(async (formData) => await invokeWebApiWrapperAsync(
async () => {
measuresForm.validateFields()
const measureParams = {
idWell: idWell,
idCategory: group.idCategory,
timestamp: new Date().toISOString(),
data: formData
}
if(editingActionName === 'add') {
await MeasureService.insert(idWell, measureParams)
} else if (editingActionName === 'edit') {
measureParams.id = displayedValues.id
measureParams.timestamp = displayedValues.timestamp
await MeasureService.update(idWell, measureParams)
}
setIsTableEditing(false)
updateMeasuresFunc()
},
setShowLoader,
`Не удалось добавить/изменить запись для скаважины "${idWell}"`,
'Добавление/изменение записи по скважине'
), [displayedValues?.id, displayedValues?.timestamp, editingActionName, group.idCategory, idWell, measuresForm, updateMeasuresFunc])
return (
<>
&nbsp;<h2>{group.title}</h2>&nbsp;
<div className={'d-flex'}>
<div className={'flex-direction-column'}>
<div className={'measure-buttons-container'}>
<div className={'w-300px mt-8px d-flex'} style={{ alignItems: 'stretch' }}>
{ isTableEditing ? (
<>
<Button key={'confirm'} className={'flex-1'} onClick={() => measuresForm.submit()}>
<SaveOutlined />
</Button>
<Button key={'decline'} className={'flex-1'} onClick={() => setIsTableEditing(false)}>
<CloseCircleOutlined />
</Button>
</>
) : (
<>
<Button key={'add'} className={'flex-1'} onClick={() => editTable('add')} disabled={disabled}>
<PlusOutlined />
</Button>
<Button key={'edit'} className={'flex-1'} onClick={() => editTable('edit')} disabled={editingDisabled}>
<EditOutlined />
</Button>
<Popconfirm style={{ flex: '1' }} title={'Удалить данные?'} onConfirm={markMeasuresAsDeleted} disabled={deleteDisabled}>
<Button key={'delete'} onClick={() => setEditingActionName('delete')} disabled={deleteDisabled}>
<DeleteOutlined style={{ margin:'auto 28px' }}/>
</Button>
</Popconfirm>
</>
)}
{additionalButtons?.(isTableEditing)}
</div>
</div>
<div className={'measure-dates mt-20px'}>
<Timeline className={'mt-12px ml-10px'}>
{data.map((item, index) => (
<Timeline.Item
key={index}
className={'measure-button'}
onClick={() => setDisplayedValues(item)}
dot={item?.id === displayedValues?.id && (
<CheckSquareOutlined className={'timeline-clock-icon'} />
)}
>
<span className={item?.id === displayedValues?.id ? 'selected-timeline' : undefined}>
{formatDate(item.timestamp) ?? 'Нет данных'}
</span>
</Timeline.Item>
))}
</Timeline>
</div>
</div>
<div className={'w-100'}>
<LoaderPortal show={showLoader}>
<Form form={measuresForm} onFinish={handleSubmitMeasuresForm}>
<View item={displayedValues?.data ?? {}} columns={editingColumns} />
</Form>
</LoaderPortal>
</div>
</div>
</>
)
})
export default MeasureTable