Страница "Измерения":

* Исправлена ошибка с ключами клеток таблиц
* Запись "Нет данных" выводится только при их отсутствии
* render-метод для дополнительных кнопок секций вынесен в константу
* Большие объекты статичных стилей перенесены в css
* Проведена мелкая стилизация кода
This commit is contained in:
Александр Сироткин 2021-12-23 18:23:21 +05:00
parent ebcd1eebb5
commit 528b7e4f7b
9 changed files with 246 additions and 237 deletions

View File

@ -1,29 +1,38 @@
import React, { useEffect, useState } from 'react'
import { Modal } from 'antd' import { Modal } from 'antd'
import { memo, useEffect, useState } from 'react'
import { Table } from '../../components/Table' import { Table } from '../../components/Table'
import { formatDate } from './MeasureTable' import { formatDate } from './MeasureTable'
import { v } from './columnsCommon' import { v } from './columnsCommon'
export const InclinometryTable = React.memo(({ group, visible, onClose }) => { const tableScroll = { y: 400, x: 1300 }
const dateColumn = {
title: 'Дата',
key: 'date',
dataIndex: 'date',
render: formatDate,
fixed: 'left',
width: '8rem',
}
export const InclinometryTable = memo(({ group, visible, onClose }) => {
const [tableColumns, setTableColumns] = useState([]) const [tableColumns, setTableColumns] = useState([])
const [tableData, setTableData] = useState([]) const [tableData, setTableData] = useState([])
useEffect(() => { useEffect(() => setTableColumns([
setTableColumns([{ dateColumn,
title: 'Дата', ...(group?.columns?.map((column) => ({
key: 'date', ...column,
dataIndex: 'date', title: v(column.title)
render: (item) => formatDate(item), })) ?? [])
fixed: 'left', ]), [group?.columns])
width: '8rem',
},
...(group?.columns?.map((column) => ({...column, title: v(column.title)})) ?? [])
])
}, [group?.columns])
useEffect(() => { useEffect(() => setTableData(group?.values?.map(row => ({
setTableData(group?.values?.map(row => ({ date: row.timestamp, ...row.data }))) date: row.timestamp,
}, [group?.values]) ...row.data
}))), [group?.values])
return !group?.columns ? null : ( return !group?.columns ? null : (
<Modal <Modal
@ -37,14 +46,9 @@ export const InclinometryTable = React.memo(({ group, visible, onClose }) => {
<Table <Table
dataSource={tableData} dataSource={tableData}
columns={tableColumns} columns={tableColumns}
scroll={{ scroll={tableScroll}
y: 400,
x: 1300
}}
bordered bordered
/> />
</Modal> </Modal>
) )
}) })
export default InclinometryTable

View File

@ -1,6 +1,6 @@
import moment from 'moment'
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { Button, Form, Input, Popconfirm, Timeline } from 'antd' import { Button, Form, Input, Popconfirm, Timeline } from 'antd'
import moment from 'moment'
import { import {
CheckSquareOutlined, CheckSquareOutlined,
EditOutlined, EditOutlined,
@ -9,15 +9,21 @@ import {
CloseCircleOutlined, CloseCircleOutlined,
DeleteOutlined DeleteOutlined
} from '@ant-design/icons' } from '@ant-design/icons'
import { View } from './View'
import LoaderPortal from '../../components/LoaderPortal' import LoaderPortal from '../../components/LoaderPortal'
import { MeasureService } from '../../services/api' import { MeasureService } from '../../services/api'
import '../../styles/index.css'
import '../../styles/measure.css'
import { invokeWebApiWrapperAsync } from '../../components/factory' import { invokeWebApiWrapperAsync } from '../../components/factory'
const dateFormat = 'YYYY.MM.DD HH:mm' import { View } from './View'
export const formatDate = (date) => date ? moment.utc(date).local().format(dateFormat) : 'Нет данных'
import '../../styles/index.css'
import '../../styles/measure.css'
export const formatDate = (date) => date ?
moment.utc(date).local().format('YYYY.MM.DD HH:mm') : 'Нет данных'
const createEditingColumns = (cols, renderDelegate) =>
cols.map(col => ({ render: renderDelegate, ...col }))
export const MeasureTable = ({idWell, group, updateMeasuresFunc, additionalButtons}) => { export const MeasureTable = ({idWell, group, updateMeasuresFunc, additionalButtons}) => {
const [showLoader, setShowLoader] = useState(false) const [showLoader, setShowLoader] = useState(false)
@ -29,11 +35,10 @@ export const MeasureTable = ({idWell, group, updateMeasuresFunc, additionalButto
const [measuresForm] = Form.useForm() const [measuresForm] = Form.useForm()
const createEditingColumns = (cols, renderDelegate) =>
cols.map(col => ({ render: renderDelegate, ...col }))
useEffect(() => { useEffect(() => {
const data = [group.defaultValue].concat(group.values ?? []) let data = [group.defaultValue]
if (group?.values?.length > 0)
data = group.values
setData(data) setData(data)
setDisplayedValues(data.at(-1)) setDisplayedValues(data.at(-1))
}, [group.defaultValue, group.values]) }, [group.defaultValue, group.values])
@ -136,11 +141,11 @@ export const MeasureTable = ({idWell, group, updateMeasuresFunc, additionalButto
key={index} key={index}
className={'measure-button'} className={'measure-button'}
onClick={() => setDisplayedValues(item)} onClick={() => setDisplayedValues(item)}
dot={item?.id !== displayedValues?.id ? null : dot={item?.id === displayedValues?.id &&
<CheckSquareOutlined className={'timeline-clock-icon'} /> <CheckSquareOutlined className={'timeline-clock-icon'} />
} }
> >
<span className={item?.id === displayedValues?.id ? 'selected-timeline' : ''}> <span className={item?.id === displayedValues?.id && 'selected-timeline'}>
{formatDate(item.timestamp)} {formatDate(item.timestamp)}
</span> </span>
</Timeline.Item> </Timeline.Item>

View File

@ -1,61 +1,50 @@
import React from 'react' import { memo, Fragment } from 'react'
import { Empty, Form } from 'antd' import { Empty, Form } from 'antd'
import { Grid, GridItem } from '../../components/Grid' import { Grid, GridItem } from '../../components/Grid'
import '../../styles/index.css' import '../../styles/index.css'
import '../../styles/measure.css'
const colsCount = 3 const colsCount = 3
const headerCellStyle = { export const View = memo(({ columns, item }) => !item || !columns?.length ? (
border:'1px solid lightgrey' <Empty key={'empty'} image={Empty.PRESENTED_IMAGE_SIMPLE} />
} ) : (
<Grid>
{columns.map((column, i) => (
<Fragment key={i}>
<GridItem
key={column.dataIndex}
row={Math.floor(i / colsCount) + 1}
col={(i % colsCount) * 2 + 1}
className={'measure-column-header'}
>
{column.title}
</GridItem>
const valueCellStyle = { <GridItem
border:'1px solid lightgrey', key={column.title}
justifyContent:'right', row={Math.floor(i / colsCount) + 1}
marginRight:'16px', col={(i % colsCount) * 2 + 2}
fontWeight:'bold', className={'measure-column-value'}
textAlign:'right', style={{ padding: 0 }}
padding: 0 >
} {column.render ? (
<Form.Item
export const View = React.memo(({columns, item}) => { key={column.dataIndex}
if (!item || !columns?.length) name={column.dataIndex}
return <Empty key='empty' image={Empty.PRESENTED_IMAGE_SIMPLE}/> style={{ padding: 0 }}
>
return ( {column.render(item[column.dataIndex])}
<Grid> </Form.Item>
{columns.map((column, i) => ( ) : (
<> <p key={column.title} className={'m-5px'}>
<GridItem {item[column.dataIndex]}
key={column.dataIndex} </p>
row={Math.floor(i / colsCount) + 1} )}
col={(i % colsCount) * 2 + 1} </GridItem>
style={headerCellStyle} </Fragment>
> ))}
{column.title} </Grid>
</GridItem> ))
<GridItem
key={column.title}
row={Math.floor(i / colsCount) + 1}
col={(i % colsCount) * 2 + 2}
style={valueCellStyle}
>
{column.render ? (
<Form.Item
key={column.dataIndex}
name={column.dataIndex}
style={{ margin: 0 }}
//rules={column.formItemRules}
>
{column.render(item[column.dataIndex])}
</Form.Item>
) : (
<p key={column.title} className='m-5px'>{item[column.dataIndex]}</p>
)}
</GridItem>
</>
))}
</Grid>
)
})

View File

@ -1,27 +1,12 @@
import React from 'react'
import { Input } from 'antd' import { Input } from 'antd'
import { RegExpIsFloat } from '../../components/Table' import { RegExpIsFloat } from '../../components/Table'
const { TextArea } = Input import '../../styles/measure.css'
export const v = (text) => ( export const v = (text) => (
<div style={{ <div className={'v-div'}>
display: 'flex', <span className={'v-span'}>
height: '180px',
justifyContent: 'center'
}}>
<span
style={{
whiteSpace: 'pre',
verticalAlign: 'center',
textAlign: 'center',
WebkitTransform: 'rotate(-90deg)',
MozTransform: 'rotate(-90deg)',
MsTransform: 'rotate(-90deg)',
OTransform: 'rotate(-90deg)',
transform: 'rotate(-90deg)',
}}>
{text} {text}
</span> </span>
</div> </div>
@ -42,7 +27,7 @@ export const numericColumnOptions = {
export const textColumnOptions = { export const textColumnOptions = {
editable: true, editable: true,
input: <TextArea/>, input: <Input.TextArea/>,
width: '3rem', width: '3rem',
formItemRules: [{ formItemRules: [{
required: true, required: true,

View File

@ -1,36 +1,37 @@
import { makeColumn } from '../../components/Table'; import { makeColumn } from '../../components/Table'
import { numericColumnOptions, textColumnOptions } from './columnsCommon' import { numericColumnOptions, textColumnOptions } from './columnsCommon'
export const columnsDrillingFluid = [ export const columnsDrillingFluid = [
makeColumn('Наименование', 'name', textColumnOptions), makeColumn('Наименование', 'name', textColumnOptions),
makeColumn('Температура, °C', 'temperature',numericColumnOptions), makeColumn('Температура, °C', 'temperature', numericColumnOptions),
makeColumn('Плотность, г/см³', 'density',numericColumnOptions), makeColumn('Плотность, г/см³', 'density', numericColumnOptions),
makeColumn('Усл. вязкость, сек', 'conditionalViscosity',numericColumnOptions), makeColumn('Усл. вязкость, сек', 'conditionalViscosity', numericColumnOptions),
makeColumn('R300', 'r300',numericColumnOptions), makeColumn('R300', 'r300', numericColumnOptions),
makeColumn('R600', 'r600',numericColumnOptions), makeColumn('R600', 'r600', numericColumnOptions),
makeColumn('R3/R6', 'r3r6',numericColumnOptions), makeColumn('R3/R6', 'r3r6', numericColumnOptions),
makeColumn('ДНС, дПа', 'dnsDpa',numericColumnOptions), makeColumn('ДНС, дПа', 'dnsDpa', numericColumnOptions),
makeColumn('Пластич. вязкость, сПз', 'plasticViscocity',numericColumnOptions), makeColumn('Пластич. вязкость, сПз', 'plasticViscocity', numericColumnOptions),
makeColumn('СНС, дПа', 'snsDpa',numericColumnOptions), makeColumn('СНС, дПа', 'snsDpa', numericColumnOptions),
makeColumn('R3/R6 49С', 'r3r649С',numericColumnOptions), makeColumn('R3/R6 49С', 'r3r649С', numericColumnOptions),
makeColumn('ДНС 49С, дПа', 'dns49Cdpa',numericColumnOptions), makeColumn('ДНС 49С, дПа', 'dns49Cdpa', numericColumnOptions),
makeColumn('Пластич. вязкость 49С, сПз', 'plasticViscocity49c',numericColumnOptions), makeColumn('Пластич. вязкость 49С, сПз', 'plasticViscocity49c', numericColumnOptions),
makeColumn('СНС 49С, дПа', 'sns49Cdpa',numericColumnOptions), makeColumn('СНС 49С, дПа', 'sns49Cdpa', numericColumnOptions),
makeColumn('МВТ, кг/м³', 'mbt',numericColumnOptions), makeColumn('МВТ, кг/м³', 'mbt', numericColumnOptions),
makeColumn('Песок, %', 'sand',numericColumnOptions), makeColumn('Песок, %', 'sand', numericColumnOptions),
makeColumn('Фильтрация, см³/30мин', 'filtering',numericColumnOptions), makeColumn('Фильтрация, см³/30мин', 'filtering', numericColumnOptions),
makeColumn('Корка, мм', 'crust',numericColumnOptions), makeColumn('Корка, мм', 'crust', numericColumnOptions),
makeColumn('KTK', 'ktk',numericColumnOptions), makeColumn('KTK', 'ktk', numericColumnOptions),
makeColumn('pH', 'ph',numericColumnOptions), makeColumn('pH', 'ph', numericColumnOptions),
makeColumn('Жесткость, мг/л', 'hardness',numericColumnOptions), makeColumn('Жесткость, мг/л', 'hardness', numericColumnOptions),
makeColumn('Хлориды, мг/л', 'chlorides',numericColumnOptions), makeColumn('Хлориды, мг/л', 'chlorides', numericColumnOptions),
makeColumn('PF', 'pf',numericColumnOptions), makeColumn('PF', 'pf', numericColumnOptions),
makeColumn('Mf', 'mf',numericColumnOptions), makeColumn('Mf', 'mf', numericColumnOptions),
makeColumn('Pm', 'pm',numericColumnOptions), makeColumn('Pm', 'pm', numericColumnOptions),
makeColumn('Твердая фаза раствора, %', 'fluidSolidPhase',numericColumnOptions), makeColumn('Твердая фаза раствора, %', 'fluidSolidPhase', numericColumnOptions),
makeColumn('Смазка, %', 'grease',numericColumnOptions), makeColumn('Смазка, %', 'grease', numericColumnOptions),
makeColumn('Карбонат кальция, кг/м³', 'calciumCarbonate',numericColumnOptions), makeColumn('Карбонат кальция, кг/м³', 'calciumCarbonate', numericColumnOptions),
]; ]
export const drillingFluidDefaultData = { export const drillingFluidDefaultData = {
idWell: 0, idWell: 0,
@ -38,33 +39,33 @@ export const drillingFluidDefaultData = {
idCategory: 0, idCategory: 0,
isDefaultData: true, isDefaultData: true,
data: { data: {
'name': 0, name: 0,
'temperature': 0, temperature: 0,
'density': 0, density: 0,
'conditionalViscosity': 0, conditionalViscosity: 0,
'r300': 0, r300: 0,
'r600': 0, r600: 0,
'r3r6': 0, r3r6: 0,
'dnsDpa': 0, dnsDpa: 0,
'plasticViscocity': 0, plasticViscocity: 0,
'snsDpa': 0, snsDpa: 0,
'r3r649С': 0, r3r649С: 0,
'dns49Cdpa': 0, dns49Cdpa: 0,
'plasticViscocity49c': 0, plasticViscocity49c: 0,
'sns49Cdpa': 0, sns49Cdpa: 0,
'mbt': 0, mbt: 0,
'sand': 0, sand: 0,
'filtering': 0, filtering: 0,
'crust': 0, crust: 0,
'ktk': 0, ktk: 0,
'ph': 0, ph: 0,
'hardness': 0, hardness: 0,
'chlorides': 0, chlorides: 0,
'pf': 0, pf: 0,
'mf': 0, mf: 0,
'pm': 0, pm: 0,
'fluidSolidPhase': 0, fluidSolidPhase: 0,
'grease': 0, grease: 0,
'calciumCarbonate': 0 calciumCarbonate: 0
} }
} }

View File

@ -1,40 +1,49 @@
import { Button } from 'antd'
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { TableOutlined } from '@ant-design/icons'
import { MeasureService } from '../../services/api'
import LoaderPortal from '../../components/LoaderPortal'
import { invokeWebApiWrapperAsync } from '../../components/factory'
import { MeasureTable } from './MeasureTable'
import { InclinometryTable } from './InclinometryTable'
import { columnsNnb, nnbDefaultData } from './nnbData' import { columnsNnb, nnbDefaultData } from './nnbData'
import { columnsMudDiagram, mudDiagramDefaultData } from './mudDiagramData' import { columnsMudDiagram, mudDiagramDefaultData } from './mudDiagramData'
import { columnsDrillingFluid, drillingFluidDefaultData } from './drillingFluidData' 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 = [ const defaultData = [
{ {
idCategory: 1, idCategory: 1,
title: 'Замер бурового раствора', title: 'Замер бурового раствора',
columns: columnsDrillingFluid, columns: columnsDrillingFluid,
values: [drillingFluidDefaultData],
defaultValue: drillingFluidDefaultData, defaultValue: drillingFluidDefaultData,
}, },
{ {
idCategory: 2, idCategory: 2,
title: 'Шламограмма', title: 'Шламограмма',
columns: columnsMudDiagram, columns: columnsMudDiagram,
values: [mudDiagramDefaultData],
defaultValue: mudDiagramDefaultData, defaultValue: mudDiagramDefaultData,
}, },
{ {
idCategory: 3, idCategory: 3,
title: 'ННБ', title: 'ННБ',
columns: columnsNnb, columns: columnsNnb,
values: [nnbDefaultData],
defaultValue: nnbDefaultData, defaultValue: nnbDefaultData,
additionalButtons: (group, idx, onClick) => (isEditing) => isEditing ? null : (
<Button
key={'table'}
className={'flex-1'}
onClick={() => onClick(idx)}
disabled={!group.values || group.values.length <= 0}
>
<TableOutlined />
</Button>
)
} }
] ]
export default function Measure({idWell}){ export const Measure = ({ idWell }) => {
const [showLoader, setShowLoader] = useState(false) const [showLoader, setShowLoader] = useState(false)
const [isMeasuresUpdating, setIsMeasuresUpdating] = useState(false) const [isMeasuresUpdating, setIsMeasuresUpdating] = useState(false)
const [data, setData] = useState(defaultData) const [data, setData] = useState(defaultData)
@ -59,26 +68,9 @@ export default function Measure({idWell}){
`Не удалось загрузить последние данные по скважине ${idWell}` `Не удалось загрузить последние данные по скважине ${idWell}`
) )
useEffect(() => {
setData(prevData => {
prevData[2].additionalButtons = (group, idx) => (isEditing) => isEditing ? null : (
<Button
key={'table'}
className={'flex-1'}
onClick={() => setTableIdx(idx)}
disabled={!group.values || group.values.length <= 0}
>
<TableOutlined />
</Button>
)
return prevData
})
}, [])
useEffect(updateCurrentValues, [idWell, isMeasuresUpdating]) useEffect(updateCurrentValues, [idWell, isMeasuresUpdating])
return <> return (
<LoaderPortal show={showLoader}> <LoaderPortal show={showLoader}>
{data.map((group, idx) => ( {data.map((group, idx) => (
<MeasureTable <MeasureTable
@ -86,7 +78,7 @@ export default function Measure({idWell}){
idWell={idWell} idWell={idWell}
group={group} group={group}
updateMeasuresFunc={() => setIsMeasuresUpdating(true)} updateMeasuresFunc={() => setIsMeasuresUpdating(true)}
additionalButtons={group.additionalButtons?.(group, idx)} additionalButtons={group.additionalButtons?.(group, idx, setTableIdx)}
/> />
))} ))}
<InclinometryTable <InclinometryTable
@ -95,5 +87,7 @@ export default function Measure({idWell}){
group={data[tableIdx]} group={data[tableIdx]}
/> />
</LoaderPortal> </LoaderPortal>
</> )
} }
export default Measure

View File

@ -32,27 +32,27 @@ export const mudDiagramDefaultData = {
idCategory: 0, idCategory: 0,
isDefaultData: true, isDefaultData: true,
data: { data: {
'probeNumber': 0, probeNumber: 0,
'probeExtractionDepth': 0, probeExtractionDepth: 0,
'sandstone': 0, sandstone: 0,
'siltstone': 0, siltstone: 0,
'argillit': 0, argillit: 0,
'brokenArgillit': 0, brokenArgillit: 0,
'coal': 0, coal: 0,
'sand': 0, sand: 0,
'clay': 0, clay: 0,
'camstone': 0, camstone: 0,
'cement': 0, cement: 0,
'summary': '-', summary: '-',
'drillingMud': 0, drillingMud: 0,
'sludge': 0, sludge: 0,
'maxSum': 0, maxSum: 0,
'methane': 0, methane: 0,
'ethane': 0, ethane: 0,
'propane': 0, propane: 0,
'butane': 0, butane: 0,
'pentane': 0, pentane: 0,
'mechanicalSpeed': 0, mechanicalSpeed: 0,
'preliminaryConclusion': '-' preliminaryConclusion: '-'
} }
} }

View File

@ -19,7 +19,7 @@ export const columnsNnb = [
makeColumn('Комментарий', 'comment', numericColumnOptions), makeColumn('Комментарий', 'comment', numericColumnOptions),
makeColumn('Разница вертикальных глубин\nмежду планом и фактом', 'depthPlanFactDifference', numericColumnOptions), makeColumn('Разница вертикальных глубин\nмежду планом и фактом', 'depthPlanFactDifference', numericColumnOptions),
makeColumn('Расстояние в пространстве\nмежду планом и фактом', 'distancePlanFactDifference', numericColumnOptions), makeColumn('Расстояние в пространстве\nмежду планом и фактом', 'distancePlanFactDifference', numericColumnOptions),
]; ]
export const nnbDefaultData = { export const nnbDefaultData = {
idWell: 0, idWell: 0,
@ -27,22 +27,22 @@ export const nnbDefaultData = {
idCategory: 0, idCategory: 0,
isDefaultData: true, isDefaultData: true,
data: { data: {
'depth': 0, depth: 0,
'zenithAngle': 0, zenithAngle: 0,
'magneticAzimuth': 0, magneticAzimuth: 0,
'trueAzimuth': 0, trueAzimuth: 0,
'directAzimuth': 0, directAzimuth: 0,
'verticalDepth': 0, verticalDepth: 0,
'absoluteMark': 0, absoluteMark: 0,
'localNorthOffset': 0, localNorthOffset: 0,
'localEastOffset': 0, localEastOffset: 0,
'outFallOffset': 0, outFallOffset: 0,
'offsetAzimuth': 0, offsetAzimuth: 0,
'areaIntensity': '-', areaIntensity: '-',
'offsetStopAngle': 0, offsetStopAngle: 0,
'zenithIntensity': 0, zenithIntensity: 0,
'comment': '-', comment: '-',
'depthPlanFactDifference': 0, depthPlanFactDifference: 0,
'distancePlanFactDifference': 0 distancePlanFactDifference: 0
} }
} }

View File

@ -34,3 +34,34 @@ input.measure-input {
.ml-10px { .ml-10px {
margin-left: 10px; margin-left: 10px;
} }
.v-div {
display: flex;
height: 180px;
justify-content: center;
}
.v-span {
white-space: pre;
vertical-align: center;
text-align: center;
-webkit-transform: rotate(-90deg);
-moz-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
-o-transform: rotate(-90deg);
transform: rotate(-90deg);
}
.measure-column-header {
border: 1px solid lightgrey;
}
.measure-column-value {
border: 1px solid lightgrey;
justify-content: right;
margin-right: 16px;
font-weight: bold;
text-align: right;
padding: 0;
}