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

* Исправлена ошибка с ключами клеток таблиц
* Запись "Нет данных" выводится только при их отсутствии
* 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 { memo, useEffect, useState } from 'react'
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([])
const tableScroll = { y: 400, x: 1300 }
useEffect(() => {
setTableColumns([{
const dateColumn = {
title: 'Дата',
key: 'date',
dataIndex: 'date',
render: (item) => formatDate(item),
render: formatDate,
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])
export const InclinometryTable = memo(({ group, visible, onClose }) => {
const [tableColumns, setTableColumns] = useState([])
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 : (
<Modal
@ -37,14 +46,9 @@ export const InclinometryTable = React.memo(({ group, visible, onClose }) => {
<Table
dataSource={tableData}
columns={tableColumns}
scroll={{
y: 400,
x: 1300
}}
scroll={tableScroll}
bordered
/>
</Modal>
)
})
export default InclinometryTable

View File

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

View File

@ -1,36 +1,24 @@
import React from 'react'
import { memo, Fragment } from 'react'
import { Empty, Form } from 'antd'
import { Grid, GridItem } from '../../components/Grid'
import '../../styles/index.css'
import '../../styles/measure.css'
const colsCount = 3
const headerCellStyle = {
border:'1px solid lightgrey'
}
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 (
export const View = memo(({ columns, item }) => !item || !columns?.length ? (
<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}
style={headerCellStyle}
className={'measure-column-header'}
>
{column.title}
</GridItem>
@ -39,23 +27,24 @@ export const View = React.memo(({columns, item}) => {
key={column.title}
row={Math.floor(i / colsCount) + 1}
col={(i % colsCount) * 2 + 2}
style={valueCellStyle}
className={'measure-column-value'}
style={{ padding: 0 }}
>
{column.render ? (
<Form.Item
key={column.dataIndex}
name={column.dataIndex}
style={{ margin: 0 }}
//rules={column.formItemRules}
style={{ padding: 0 }}
>
{column.render(item[column.dataIndex])}
</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>
</>
</Fragment>
))}
</Grid>
)
})
))

View File

@ -1,27 +1,12 @@
import React from 'react'
import { Input } from 'antd'
import { RegExpIsFloat } from '../../components/Table'
const { TextArea } = Input
import '../../styles/measure.css'
export const v = (text) => (
<div style={{
display: 'flex',
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)',
}}>
<div className={'v-div'}>
<span className={'v-span'}>
{text}
</span>
</div>
@ -42,7 +27,7 @@ export const numericColumnOptions = {
export const textColumnOptions = {
editable: true,
input: <TextArea/>,
input: <Input.TextArea/>,
width: '3rem',
formItemRules: [{
required: true,

View File

@ -1,4 +1,5 @@
import { makeColumn } from '../../components/Table';
import { makeColumn } from '../../components/Table'
import { numericColumnOptions, textColumnOptions } from './columnsCommon'
export const columnsDrillingFluid = [
@ -30,7 +31,7 @@ export const columnsDrillingFluid = [
makeColumn('Твердая фаза раствора, %', 'fluidSolidPhase', numericColumnOptions),
makeColumn('Смазка, %', 'grease', numericColumnOptions),
makeColumn('Карбонат кальция, кг/м³', 'calciumCarbonate', numericColumnOptions),
];
]
export const drillingFluidDefaultData = {
idWell: 0,
@ -38,33 +39,33 @@ export const drillingFluidDefaultData = {
idCategory: 0,
isDefaultData: true,
data: {
'name': 0,
'temperature': 0,
'density': 0,
'conditionalViscosity': 0,
'r300': 0,
'r600': 0,
'r3r6': 0,
'dnsDpa': 0,
'plasticViscocity': 0,
'snsDpa': 0,
'r3r649С': 0,
'dns49Cdpa': 0,
'plasticViscocity49c': 0,
'sns49Cdpa': 0,
'mbt': 0,
'sand': 0,
'filtering': 0,
'crust': 0,
'ktk': 0,
'ph': 0,
'hardness': 0,
'chlorides': 0,
'pf': 0,
'mf': 0,
'pm': 0,
'fluidSolidPhase': 0,
'grease': 0,
'calciumCarbonate': 0
name: 0,
temperature: 0,
density: 0,
conditionalViscosity: 0,
r300: 0,
r600: 0,
r3r6: 0,
dnsDpa: 0,
plasticViscocity: 0,
snsDpa: 0,
r3r649С: 0,
dns49Cdpa: 0,
plasticViscocity49c: 0,
sns49Cdpa: 0,
mbt: 0,
sand: 0,
filtering: 0,
crust: 0,
ktk: 0,
ph: 0,
hardness: 0,
chlorides: 0,
pf: 0,
mf: 0,
pm: 0,
fluidSolidPhase: 0,
grease: 0,
calciumCarbonate: 0
}
}

View File

@ -1,40 +1,49 @@
import { Button } from 'antd'
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 { 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,
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 [isMeasuresUpdating, setIsMeasuresUpdating] = useState(false)
const [data, setData] = useState(defaultData)
@ -59,26 +68,9 @@ export default function Measure({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])
return <>
return (
<LoaderPortal show={showLoader}>
{data.map((group, idx) => (
<MeasureTable
@ -86,7 +78,7 @@ export default function Measure({idWell}){
idWell={idWell}
group={group}
updateMeasuresFunc={() => setIsMeasuresUpdating(true)}
additionalButtons={group.additionalButtons?.(group, idx)}
additionalButtons={group.additionalButtons?.(group, idx, setTableIdx)}
/>
))}
<InclinometryTable
@ -95,5 +87,7 @@ export default function Measure({idWell}){
group={data[tableIdx]}
/>
</LoaderPortal>
</>
)
}
export default Measure

View File

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

View File

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

View File

@ -34,3 +34,34 @@ input.measure-input {
.ml-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;
}