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

* Исправлена ошибка с ключами клеток таблиц
* Запись "Нет данных" выводится только при их отсутствии
* 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 [tableColumns, setTableColumns] = useState([])
const [tableData, setTableData] = useState([])
useEffect(() => { const dateColumn = {
setTableColumns([{
title: 'Дата', title: 'Дата',
key: 'date', key: 'date',
dataIndex: 'date', dataIndex: 'date',
render: (item) => formatDate(item), render: formatDate,
fixed: 'left', fixed: 'left',
width: '8rem', width: '8rem',
}, }
...(group?.columns?.map((column) => ({...column, title: v(column.title)})) ?? [])
])
}, [group?.columns])
useEffect(() => { export const InclinometryTable = memo(({ group, visible, onClose }) => {
setTableData(group?.values?.map(row => ({ date: row.timestamp, ...row.data }))) const [tableColumns, setTableColumns] = useState([])
}, [group?.values]) const [tableData, setTableData] = useState([])
useEffect(() => setTableColumns([
dateColumn,
...(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 : ( 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,36 +1,24 @@
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} />
} ) : (
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 <Empty key='empty' image={Empty.PRESENTED_IMAGE_SIMPLE}/>
return (
<Grid> <Grid>
{columns.map((column, i) => ( {columns.map((column, i) => (
<> <Fragment key={i}>
<GridItem <GridItem
key={column.dataIndex} key={column.dataIndex}
row={Math.floor(i / colsCount) + 1} row={Math.floor(i / colsCount) + 1}
col={(i % colsCount) * 2 + 1} col={(i % colsCount) * 2 + 1}
style={headerCellStyle} className={'measure-column-header'}
> >
{column.title} {column.title}
</GridItem> </GridItem>
@ -39,23 +27,24 @@ export const View = React.memo(({columns, item}) => {
key={column.title} key={column.title}
row={Math.floor(i / colsCount) + 1} row={Math.floor(i / colsCount) + 1}
col={(i % colsCount) * 2 + 2} col={(i % colsCount) * 2 + 2}
style={valueCellStyle} className={'measure-column-value'}
style={{ padding: 0 }}
> >
{column.render ? ( {column.render ? (
<Form.Item <Form.Item
key={column.dataIndex} key={column.dataIndex}
name={column.dataIndex} name={column.dataIndex}
style={{ margin: 0 }} style={{ padding: 0 }}
//rules={column.formItemRules}
> >
{column.render(item[column.dataIndex])} {column.render(item[column.dataIndex])}
</Form.Item> </Form.Item>
) : ( ) : (
<p key={column.title} className='m-5px'>{item[column.dataIndex]}</p> <p key={column.title} className={'m-5px'}>
{item[column.dataIndex]}
</p>
)} )}
</GridItem> </GridItem>
</> </Fragment>
))} ))}
</Grid> </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,4 +1,5 @@
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 = [
@ -30,7 +31,7 @@ export const columnsDrillingFluid = [
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;
}