diff --git a/src/pages/Measure/InclinometryTable.jsx b/src/pages/Measure/InclinometryTable.jsx new file mode 100644 index 0000000..fe04957 --- /dev/null +++ b/src/pages/Measure/InclinometryTable.jsx @@ -0,0 +1,50 @@ +import React, { useEffect, useState } from 'react' +import { Modal } from 'antd' +import { Table } from '../../components/Table' +import { formatDate } from './MeasureTable' +import { v } from './columnsCommon' + +export const InclinometryTable = React.memo(({ group, visible, onClose }) => { + const [tableColumns, setTableColumns] = useState([]) + const [tableData, setTableData] = useState([]) + + useEffect(() => { + setTableColumns([{ + title: 'Дата', + key: 'date', + dataIndex: 'date', + render: (item) => formatDate(item), + fixed: 'left', + width: '8rem', + }, + ...(group?.columns?.map((column) => ({...column, title: v(column.title)})) ?? []) + ]) + }, [group?.columns]) + + useEffect(() => { + setTableData(group?.values?.map(row => ({ date: row.timestamp, ...row.data }))) + }, [group?.values]) + + return !group?.columns ? null : ( + + + + ) +}) + +export default InclinometryTable diff --git a/src/pages/Measure/MeasureTable.jsx b/src/pages/Measure/MeasureTable.jsx index 4831ec6..04fbff9 100644 --- a/src/pages/Measure/MeasureTable.jsx +++ b/src/pages/Measure/MeasureTable.jsx @@ -1,198 +1,161 @@ import { useState, useEffect } from 'react' import { Button, Form, Input, Popconfirm, Timeline } from 'antd' import moment from 'moment' -import { CheckSquareOutlined, - EditOutlined, - SaveOutlined, - PlusOutlined, - CloseCircleOutlined, - DeleteOutlined } from '@ant-design/icons' +import { + CheckSquareOutlined, + EditOutlined, + SaveOutlined, + PlusOutlined, + CloseCircleOutlined, + DeleteOutlined +} from '@ant-design/icons' import { View } from './View' import LoaderPortal from '../../components/LoaderPortal' import { MeasureService } from '../../services/api' import '../../styles/index.css' import '../../styles/measure.css' +import { invokeWebApiWrapperAsync } from '../../components/factory' -const format='YYYY.MM.DD HH:mm' +const dateFormat = 'YYYY.MM.DD HH:mm' +export const formatDate = (date) => date ? moment.utc(date).local().format(dateFormat) : 'Нет данных' -export const MeasureTable = ({idWell, idCategory, title, columns, values, updateMeasuresFunc}) => { +export const MeasureTable = ({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 [data, setData] = useState([]) - const [showLoader, setShowLoader] = useState(false); - const [displayedValues, setDisplayedValues] = useState({}); - const [editingColumns, setEditingColumns] = useState(columns); - const [isTableEditing, setIsTableEditing] = useState(false); - const [editingActionName, setEditingActionName] = useState(''); - - const [measuresForm] = Form.useForm(); + const [measuresForm] = Form.useForm() const createEditingColumns = (cols, renderDelegate) => - cols.map(col => - ({ render: renderDelegate, - ...col - }) - ) + cols.map(col => ({ render: renderDelegate, ...col })) useEffect(() => { - const defaultValuesToDisplay = values[values.length-1] - - setDisplayedValues(defaultValuesToDisplay) - }, [values]) + const data = [group.defaultValue].concat(group.values ?? []) + setData(data) + setDisplayedValues(data.at(-1)) + }, [group.defaultValue, group.values]) useEffect(() => { - let switchableColumns = [] - - isTableEditing - ? switchableColumns = createEditingColumns(columns, () => ) - : switchableColumns = createEditingColumns(columns, null) + const switchableColumns = createEditingColumns( + group.columns, + isTableEditing ? () => : null + ) if(editingActionName === 'edit') - measuresForm.setFieldsValue(displayedValues?.data); + measuresForm.setFieldsValue(displayedValues?.data) else if(editingActionName === 'add') measuresForm.resetFields() setEditingColumns(switchableColumns) - }, [isTableEditing, columns, editingActionName, displayedValues?.data, measuresForm]) + }, [isTableEditing, group.columns, editingActionName, displayedValues?.data, measuresForm]) - const markMeasuresAsDeleted = async () => { - setShowLoader(true) - await MeasureService.markAsDelete(idWell, displayedValues.id) - updateMeasuresFunc() - setShowLoader(false) + const markMeasuresAsDeleted = async () => await invokeWebApiWrapperAsync( + async () => { + await MeasureService.markAsDelete(idWell, displayedValues.id) + updateMeasuresFunc() + }, + setShowLoader, + `Не удалось удалить запись ${displayedValues.id} для скважины "${idWell}"` + ) + + const isDataDefault = () => !!displayedValues?.isDefaultData + + const editTable = (action) => { + setEditingActionName(action) + setIsTableEditing(true) } - const checkIsDataDefault = () => - displayedValues?.isDefaultData ? true : false + const handleSubmitMeasuresForm = async (formData) => await invokeWebApiWrapperAsync( + async () => { + measuresForm.validateFields() - const crudButtons = -
- - - markMeasuresAsDeleted()} - disabled={checkIsDataDefault()} - > - - -
+ const measureParams = { + idWell: idWell, + idCategory: group.idCategory, + timestamp: new Date().toISOString(), + data: formData + } - const confirmButtons = -
-
- - -
-
- - let handleSubmitMeasuresForm = async (formData) => { - measuresForm.validateFields() + 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) + } - const measureParams = { - idWell: idWell, - idCategory: idCategory, - timestamp: new Date().toISOString(), - data: formData - } + setIsTableEditing(false) + updateMeasuresFunc() + }, + setShowLoader, + `Не удалось добавить/изменить запись для скаважины "${idWell}"` + ) - setShowLoader(true) + return ( + <> +  

{group.title}

  +
+
+
+
+ { isTableEditing ? ( + <> + + + + ) : ( + <> + + + + + + + )} + {additionalButtons?.(isTableEditing)} +
+
- 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(false) - } - - return <> -   -

{title}

-   -
-
-
- {isTableEditing - ? confirmButtons - : crudButtons - } +
+ + {data.map((item, index) => + setDisplayedValues(item)} + dot={item?.id !== displayedValues?.id ? null : + + } + > + + {formatDate(item.timestamp)} + + + )} + +
- -
- - {values.map((item, index) => - setDisplayedValues(item)} - dot={item?.id === displayedValues?.id - ? - : null} - > - - {item.timestamp ? moment.utc(item.timestamp).local().format(format) : 'Нет данных'} - - - )} - +
+ +
+ + +
-
- -
- - -
-
-
- -} \ No newline at end of file + + ) +} diff --git a/src/pages/Measure/View.jsx b/src/pages/Measure/View.jsx index e097f4c..a42cbbe 100644 --- a/src/pages/Measure/View.jsx +++ b/src/pages/Measure/View.jsx @@ -1,62 +1,61 @@ -import { Empty, Form } from 'antd'; -import {Grid, GridItem} from '../../components/Grid' +import React from 'react' +import { Empty, Form } from 'antd' +import { Grid, GridItem } from '../../components/Grid' import '../../styles/index.css' -const renderSwitchableColumn = (column, itm) => { - if(column.render) { - return ( - - {column.render(itm[column.dataIndex])} - - ) - } +const colsCount = 3 - return

{itm[column.dataIndex]}

+const headerCellStyle = { + border:'1px solid lightgrey' } -export const View = ({columns, item}) => { +const valueCellStyle = { + border:'1px solid lightgrey', + justifyContent:'right', + marginRight:'16px', + fontWeight:'bold', + textAlign:'right', + padding: 0 +} + +export const View = React.memo(({columns, item}) => { if (!item || !columns?.length) return - const colsCount = 3 - const viewItems = columns.map( (column, i) => { - const row = Math.floor(i / colsCount) + 1 - const colb = i % colsCount - - return <> - - {column.title} - - - - {renderSwitchableColumn(column, item)} - - - }) - - return <> + return ( - {viewItems} + {columns.map((column, i) => ( + <> + + {column.title} + + + + {column.render ? ( + + {column.render(item[column.dataIndex])} + + ) : ( +

{item[column.dataIndex]}

+ )} +
+ + ))}
- -} \ No newline at end of file + ) +}) \ No newline at end of file diff --git a/src/pages/Measure/index.jsx b/src/pages/Measure/index.jsx index e4b6dd9..bdc6d5d 100644 --- a/src/pages/Measure/index.jsx +++ b/src/pages/Measure/index.jsx @@ -1,64 +1,99 @@ import { useState, useEffect } from 'react' -import { columnsMudDiagram} from './mudDiagramData' -import { mudDiagramDefaultData} from './mudDiagramData' -import { columnsDrillingFluid} from './drillingFluidData' -import { drillingFluidDefaultData} from './drillingFluidData' -import { columnsNnb } from './nnbData' -import { nnbDefaultData } from './nnbData' +import { columnsNnb, nnbDefaultData } from './nnbData' +import { columnsMudDiagram, mudDiagramDefaultData } from './mudDiagramData' +import { columnsDrillingFluid, drillingFluidDefaultData } from './drillingFluidData' import { invokeWebApiWrapperAsync } from '../../components/factory' import { MeasureService } from '../../services/api' import LoaderPortal from '../../components/LoaderPortal' import { MeasureTable } from './MeasureTable' +import InclinometryTable from './InclinometryTable' +import { Button } from 'antd' +import { TableOutlined } from '@ant-design/icons' + +const defaultData = [ + { + idCategory: 1, + title: 'Замер бурового раствора', + columns: columnsDrillingFluid, + values: [drillingFluidDefaultData], + defaultValue: drillingFluidDefaultData, + }, + { + idCategory: 2, + title: 'Шламограмма', + columns: columnsMudDiagram, + values: [mudDiagramDefaultData], + defaultValue: mudDiagramDefaultData, + }, + { + idCategory: 3, + title: 'ННБ', + columns: columnsNnb, + values: [nnbDefaultData], + defaultValue: nnbDefaultData, + } +] export default function Measure({idWell}){ const [showLoader, setShowLoader] = useState(false) - const [fluidValues, setFluidValues] = useState([]) - const [mudValues, setMudValues] = useState([]) - const [nnbValues, setNnbValues] = useState([]) const [isMeasuresUpdating, setIsMeasuresUpdating] = useState(false) + const [data, setData] = useState(defaultData) + const [tableIdx, setTableIdx] = useState(-1) - const updateCurrentValues = () => invokeWebApiWrapperAsync(async()=>{ - const measures = await MeasureService.getHisory(idWell) - setIsMeasuresUpdating(false) + const updateCurrentValues = () => invokeWebApiWrapperAsync( + async () => { + const measures = await MeasureService.getHisory(idWell) + setIsMeasuresUpdating(false) - const fluids = measures.filter(el => el.idCategory === 1) - setFluidValues(fluids.length ? fluids : [drillingFluidDefaultData]) - const muds = measures.filter(el => el.idCategory === 2) - setMudValues(muds.length ? muds : [mudDiagramDefaultData]) - const nnbs = measures.filter(el => el.idCategory === 3) - setNnbValues(nnbs.length ? nnbs : [nnbDefaultData]) - } - ,setShowLoader - ,`Не удалось загрузить последние данные по скважине ${idWell}`) + setData(prevData => { + prevData.forEach(el => el.values = []) + measures.forEach(el => { + const idx = prevData.findIndex(group => el.idCategory === group.idCategory) + if (idx >= 0) + prevData[idx].values.push(el) + }) + return prevData + }) + }, + setShowLoader, + `Не удалось загрузить последние данные по скважине ${idWell}` + ) + + useEffect(() => { + setData(prevData => { + data[2].additionalButtons = (group, idx) => (isEditing) => isEditing ? null : ( + + ) + + return prevData + }) + }, []) useEffect(updateCurrentValues, [idWell, isMeasuresUpdating]) - return <> + return <> - setIsMeasuresUpdating(true)} - /> - setIsMeasuresUpdating(true)} - /> - setIsMeasuresUpdating(true)} + {data.map((group, idx) => ( + setIsMeasuresUpdating(true)} + additionalButtons={group.additionalButtons?.(group, idx)} + /> + ))} + = 0} + onClose={() => setTableIdx(-1)} + group={data[tableIdx]} /> -} \ No newline at end of file +} diff --git a/src/styles/index.css b/src/styles/index.css index 39aef5a..4103d37 100644 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -23,6 +23,10 @@ body { display: none; } +.flex-1 { + flex: 1; +} + .w-15 { width: 15% }