diff --git a/src/components/PeriodPicker.tsx b/src/components/PeriodPicker.tsx index 88bbe6a..90ff7d6 100644 --- a/src/components/PeriodPicker.tsx +++ b/src/components/PeriodPicker.tsx @@ -16,10 +16,12 @@ const timePeriodCollection = [ type PeriodPickerProps = { defaultValue?: number onChange?: (value: number) => void + [other: string]: any } -export const PeriodPicker = ({ defaultValue = defaultPeriod, onChange }: PeriodPickerProps) => ( +export const PeriodPicker = ({ defaultValue = defaultPeriod, onChange, ...other }: PeriodPickerProps) => ( , + render: (val) => setpointNames.find((name) => name.value === val)?.label + }, { + title: 'Значение', + dataIndex: 'value', + editable: true, + isRequired: true, + width: 125, + input: `${value}`.replace(',', '.')}/>, + render: makeNumericRender(1), + align: 'right' + } + ] + + const onAdd = async (sp) => setSetpoints((prevSp) => { + sp.key = Date.now() + prevSp.push(sp) + return prevSp + }) + + const onEdit = async (sp) => setSetpoints((prevSp) => { + const idx = prevSp.findIndex((val) => val.key === sp.key) + prevSp[idx] = sp + return prevSp + }) + + const onDelete = async (sp) => setSetpoints((prevSp) => { + const idx = prevSp.findIndex((val) => val.key === sp.key) + prevSp.splice(idx, 1) + return prevSp + }) + + const onModalOk = () => invokeWebApiWrapperAsync( + async () => { + const setpointsObject = setpoints.reduce((obj, sp) => (obj[sp.name] = sp.value, obj), {}) + const request = { + uploadDate: new Date(), + obsolescenceSec: expirePeriod, + setpoints: setpointsObject, + comment: comment + } + await SetpointsService.insert(idWell, request) + onClose(true) + }, + setIsLoading, + `Не удалось отправить уставки по скважине "${idWell}"` + ) + + return ( + + + + Период актуальности рекомендаций: + + + + + Комментарий: + + setComment(e.target.value)} + value={comment} + required + /> + + + + + + + + + ) +} diff --git a/src/pages/TelemetryView/SetpointViewer.jsx b/src/pages/TelemetryView/SetpointViewer.jsx new file mode 100644 index 0000000..feb2240 --- /dev/null +++ b/src/pages/TelemetryView/SetpointViewer.jsx @@ -0,0 +1,77 @@ +import moment from 'moment' +import { memo } from 'react' +import { Modal, Input } from 'antd' +import { Table } from '../../components/Table' +import { UserView } from '../../components/UserView' +import { Grid, GridItem } from '../../components/Grid' +import { periodToString } from '../../utils/datetime' + +export const setpointStatus = { + 0: 'Неизвестно', + 1: 'Ожидает отправки', + 2: 'Отправлено', + 3: 'Принято оператором', + 4: 'Отклонено оператором', + 5: 'Устарело', +} + +export const getSetpointStatus = (id) => { + if (!id || Object.keys(setpointStatus).every((idx) => Number(idx) !== id)) + return setpointStatus[0] + return setpointStatus[id] +} + +const columns = [ + { title: 'Название', dataIndex: 'name' }, + { title: 'Значение', dataIndex: 'value' }, +] + +export const SetpointViewer = memo(({ setpoint, visible, onClose, setpointNames }) => { + let date = moment(setpoint?.uploadDate).format('DD MMM YYYY, HH:mm:ss') + let setpoints = [] + if (setpoint) { + setpoints = Object.keys(setpoint?.setpoints).map((name) => ({ + name: setpointNames.find(spName => spName.value === name)?.label, + value: setpoint.setpoints[name] + })) + } + + return ( + + + Дата рекомендаций: + {date} + + Автор: + + + Статус: + {getSetpointStatus(setpoint?.idState)} + + Период актуальности рекомендаций: + {periodToString(setpoint?.obsolescenceSec)} + + Комментарий: + + + + + + + + + + ) +}) diff --git a/src/pages/TelemetryView/Setpoints.jsx b/src/pages/TelemetryView/Setpoints.jsx index ad2701e..1f6846a 100644 --- a/src/pages/TelemetryView/Setpoints.jsx +++ b/src/pages/TelemetryView/Setpoints.jsx @@ -1,41 +1,25 @@ -import { Button, Input, Modal, Select } from 'antd' -import { useState } from 'react' -import { invokeWebApiWrapperAsync } from '../../components/factory' +import moment from 'moment' +import { Button, Modal } from 'antd' +import { useState, useEffect } from 'react' +import { Table } from '../../components/Table' +import { UserView } from '../../components/UserView' import LoaderPortal from '../../components/LoaderPortal' -import PeriodPicker, { defaultPeriod } from '../../components/PeriodPicker' -import { EditableTable, makeNumericRender } from '../../components/Table' +import { invokeWebApiWrapperAsync } from '../../components/factory' +import { makeStringCutter } from '../../utils/string' import { SetpointsService } from '../../services/api' +import { SetpointSender } from './SetpointSender' +import { SetpointViewer, getSetpointStatus } from './SetpointViewer' export const Setpoints = ({ idWell, ...other }) => { - const [isModalShown, setIsModalShown] = useState(false) + const [isModalVisible, setIsModalVisible] = useState(false) + const [isSenderVisible, setIsSenderVisible] = useState(false) + const [isViewerVisible, setIsViewerVisible] = useState(false) const [isLoading, setIsLoading] = useState(false) - const [isUploading, setIsUploading] = useState(false) - const [setpointNames, setSetpointNames] = useState([]) const [setpoints, setSetpoints] = useState([]) - const [comment, setComment] = useState('') - const [expirePeriod, setExpirePeriod] = useState(defaultPeriod) + const [selected, setSelected] = useState(null) + const [setpointNames, setSetpointNames] = useState([]) - const columns = [ - { - title: 'Наименование установки', - dataIndex: 'name', - editable: true, - isRequired: true, - width: 200, - input:
- Комментарий: - setComment(e.value)} - value={comment} - required /> + + setIsViewerVisible(false)} + /> ) } diff --git a/src/pages/TelemetryView/index.jsx b/src/pages/TelemetryView/index.jsx index 159d671..8b522bd 100644 --- a/src/pages/TelemetryView/index.jsx +++ b/src/pages/TelemetryView/index.jsx @@ -42,7 +42,7 @@ const blockHeightGroup = [ color: '#333', showLabels: true }, { - label: 'wellDepth', + label: 'Глубина скважины', units: 'м', xAccessorName: 'wellDepth', yAccessorName: 'date', @@ -59,7 +59,7 @@ const blockHeightGroup = [ showLabels: true, showLine: true }, { - label: 'flowLimits', + label: 'Предел расхода', units: 'л/с', xAccessorName: 'flow', yAccessorName: 'date', @@ -77,7 +77,7 @@ const blockSpeedGroup = [ color: '#0a0', showLabels: true, }, { - label: 'blockSpeedSp', + label: 'Скорость заданная', units: 'м/ч', xAccessorName: 'blockSpeedSp', yAccessorName: 'date', @@ -96,7 +96,7 @@ const pressureGroup = [ color: '#c00', showLabels: true }, { - label: 'pressureSp', + label: 'Давление заданное', units: 'атм', xAccessorName: 'pressureSp', yAccessorName: 'date', @@ -104,7 +104,7 @@ const pressureGroup = [ footer: 'SP', dash }, { - label: 'pressureIdle', + label: 'Давление ХХ', units: 'атм', xAccessorName: 'pressureIdle', yAccessorName: 'date', @@ -112,7 +112,7 @@ const pressureGroup = [ footer: 'IDLE', dash }, { - label: 'pressureDeltaLimitMax', + label: 'Перепад давления максимальный', units: 'атм', xAccessorName: 'pressureDeltaLimitMax', yAccessorName: 'date', @@ -120,7 +120,7 @@ const pressureGroup = [ footer: true, dash }, { - label: 'pressureLimits', + label: 'Предел давления заданный', units: 'атм', xAccessorName: 'pressure', yAccessorName: 'date', @@ -138,7 +138,7 @@ const axialLoadGroup = [ color: '#00a', showLabels: true }, { - label: 'axialLoadSp', + label: 'Осевая нагрузка заданная', units: 'т', xAccessorName: 'axialLoadSp', yAccessorName: 'date', @@ -146,7 +146,7 @@ const axialLoadGroup = [ footer: 'SP', dash }, { - label: 'axialLoadLimitMax', + label: 'Осевая нагрузка максимальная', units: 'т', xAccessorName: 'axialLoadLimitMax', yAccessorName: 'date', @@ -154,7 +154,7 @@ const axialLoadGroup = [ footer: true, dash }, { - label: 'axialLoadLimits', + label: 'Пределы осевой нагрузки', units: 'т', xAccessorName: 'axialLoad', yAccessorName: 'date', @@ -172,7 +172,7 @@ const hookWeightGroup = [ color: '#0aa', showLabels: true }, { - label: 'hookWeightIdle', + label: 'Вес инструмента ХХ', units: 'т', xAccessorName: 'hookWeightIdle', yAccessorName: 'date', @@ -180,7 +180,7 @@ const hookWeightGroup = [ footer: 'IDLE', dash }, { - label: 'hookWeightLimitMin', + label: 'Вес инструмента минимальный', units: 'т', xAccessorName: 'hookWeightLimitMin', yAccessorName: 'date', @@ -188,7 +188,7 @@ const hookWeightGroup = [ footer: true, dash }, { - label: 'hookWeightLimitMax', + label: 'Вес инструмента максимальный', units: 'т', xAccessorName: 'hookWeightLimitMax', yAccessorName: 'date', @@ -203,7 +203,7 @@ const hookWeightGroup = [ color: '#aa0', showLabels: true }, { - label: 'rotorSpeedLimits', + label: 'Скорость вращения ВСП максимальная', units: 'об/мин', xAccessorName: 'rotorSpeed', yAccessorName: 'date', @@ -237,7 +237,7 @@ const rotorTorqueGroup = [ footer: 'IDLE', dash }, { - label: 'rotorTorqueLimitMax', + label: 'Момент максимальный', units: 'кН·м', xAccessorName: 'rotorTorqueLimitMax', yAccessorName: 'date', @@ -245,7 +245,7 @@ const rotorTorqueGroup = [ footer: true, dash }, { - label: 'rotorTorqueLimits', + label: 'Ограничения момента', units: 'кН·м', xAccessorName: 'rotorTorque', yAccessorName: 'date', diff --git a/src/utils/datetime.ts b/src/utils/datetime.ts new file mode 100644 index 0000000..2f2bb63 --- /dev/null +++ b/src/utils/datetime.ts @@ -0,0 +1,10 @@ +export const periodToString = (time?: number) => { + if (!time) return '00:00:00' + const hours = Math.floor(time / 3600) + const minutes = Math.floor(time / 60 - hours * 60) + const seconds = Math.floor(time - hours * 3600 - minutes * 60) + + const toFixed = (num: number) => `${num}`.padStart(2, '0') + + return `${toFixed(hours)}:${toFixed(minutes)}:${toFixed(seconds)}` +} diff --git a/src/utils/string.ts b/src/utils/string.ts new file mode 100644 index 0000000..debbcf3 --- /dev/null +++ b/src/utils/string.ts @@ -0,0 +1,8 @@ +export const makeStringCutter = (maxLength = 100, separator = ' ', suffix = '...') => (comment?: string) => { + if (!comment || comment.length < maxLength) + return comment + let lastSep = comment.lastIndexOf(separator, maxLength) + if (lastSep < 0) + return comment.substring(0, maxLength - suffix.length) + suffix + return comment.substring(0, lastSep) +}