From 7f2d337b4f58bdcd56bbd3ea1d5859a40253c233 Mon Sep 17 00:00:00 2001 From: goodmice Date: Thu, 6 Oct 2022 14:37:39 +0500 Subject: [PATCH] =?UTF-8?q?*=20=D0=92=D1=8B=D0=B4=D0=B5=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=20=D1=81=D1=82=D0=B8=D0=BB=D1=8C=20=D0=B1=D0=BB=D0=BE=D0=BA?= =?UTF-8?q?=D0=B0=20=D1=84=D0=B8=D0=BB=D1=8C=D1=82=D1=80=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D0=B8=20*=20=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=20=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86=D0=B0=20"=D0=9D=D0=B0?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B0"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Telemetry/Messages.jsx | 1 + src/pages/Telemetry/OperationTime/index.jsx | 128 ++++++++++++++++ src/pages/Telemetry/OperationTime/index.tsx | 153 -------------------- src/styles/d3.less | 4 +- src/styles/filter.less | 22 +++ src/styles/message.less | 23 --- src/styles/operation_time.less | 3 + 7 files changed, 156 insertions(+), 178 deletions(-) create mode 100644 src/pages/Telemetry/OperationTime/index.jsx delete mode 100644 src/pages/Telemetry/OperationTime/index.tsx create mode 100644 src/styles/filter.less create mode 100644 src/styles/operation_time.less diff --git a/src/pages/Telemetry/Messages.jsx b/src/pages/Telemetry/Messages.jsx index 824e38d..bc845d4 100755 --- a/src/pages/Telemetry/Messages.jsx +++ b/src/pages/Telemetry/Messages.jsx @@ -11,6 +11,7 @@ import { makeColumn, makeDateColumn, makeNumericColumn, makeNumericSorter, makeT import { wrapPrivateComponent } from '@utils' import { MessageService } from '@api' +import '@styles/filter.less' import '@styles/message.less' const pageSize = 26 diff --git a/src/pages/Telemetry/OperationTime/index.jsx b/src/pages/Telemetry/OperationTime/index.jsx new file mode 100644 index 0000000..9351aae --- /dev/null +++ b/src/pages/Telemetry/OperationTime/index.jsx @@ -0,0 +1,128 @@ +import { memo, useEffect, useMemo, useState } from 'react' +import { Select } from 'antd' +import moment from 'moment' + +import { useWell } from '@asb/context' +import LoaderPortal from '@components/LoaderPortal' +import { invokeWebApiWrapperAsync } from '@components/factory' +import D3HorizontalPercentChart from '@components/d3/D3HorizontalPercentChart' +import { DateRangeWrapper, makeColumn, makeNumericColumn, makeNumericRender, makeTextColumn, Table } from '@components/Table' +import { arrayOrDefault, range, wrapPrivateComponent } from '@utils' +import { SubsystemOperationTimeService } from '@api' + +import '@styles/filter.less' +import '@styles/operation_time.less' + +const subsystemColors = [ + '#1abc9c', '#16a085', '#2ecc71', '#27ae60', + '#3498db', '#2980b9', '#9b59b6', '#8e44ad', + '#34495e', '#2c3e50', '#f1c40f', '#f39c12', + '#e67e22', '#d35400', '#e74c3c', '#c0392b', + '#ecf0f1', '#bdc3c7', '#95a5a6', '#7f8c8d', +] + +const tableColumns = [ + makeColumn('Цвет', 'color', { width: 50, render: (backgroundColor) => ( +
+ )}), + makeTextColumn('Подсистема', 'subsystemName'), + makeNumericColumn('Использование, %', 'kUsage', undefined, undefined, val => (+val * 100).toFixed(2)), + makeNumericColumn('Проходка, м', 'sumDepthInterval'), + makeNumericColumn('Время работы, ч', 'usedTimeHours'), + makeNumericColumn('Кол-во запусков', 'operationCount', undefined, undefined, makeNumericRender(0)), +] + +// Выбор доступен только до текущей даты +const disabledDates = (current) => current && moment(current).isAfter(moment(), 'day', '[]') +// Выбор доступен только до текущего времени +const disabledTimes = (date) => ({ + disabledHours: () => range(24).filter(h => date && moment(date).hours(h).isAfter(moment(), 'hour', '[]')), + disabledMinutes: () => range(60).filter(m => date && moment(date).minutes(m).isAfter(moment(), 'minute', '[]')), + disabledSeconds: () => range(60).filter(s => date && moment(date).seconds(s).isBetween(moment(), 'second', '[]')) +}) + +export const OperationTime = memo(() => { + const [showLoader, setShowLoader] = useState(false) + const [data, setData] = useState([]) + const [selected, setSelected] = useState([]) + const [dateRange, setDateRange] = useState([]) + const [well] = useWell() + + // Создаём массив пунктов для селектора подсистем + const typeOptions = useMemo(() => data.map((d) => ({ label: d.subsystemName, value: d.idSubsystem })), [data]) + // Фильтруем данные по выбранным подсистемам + const selectedData = useMemo(() => data.filter((d) => selected.includes(d.idSubsystem)), [selected, data]) + // Подготавливаем данные для отображения на графике + const chartData = useMemo(() => selectedData.map((d) => ({ + name: d.subsystemName, + percent: d.kUsage * 100, + color: d.color, + })), [selectedData]) + + useEffect(() => { + invokeWebApiWrapperAsync( + async () => { + if (!well.id) return + + // Ограничение задаётся только если выбраны обе даты + const startDate = dateRange[1] ? dateRange[0]?.toISOString() : undefined + const endDate = dateRange[1]?.toISOString() + + const data = await SubsystemOperationTimeService.getStat(well.id, undefined, startDate, endDate) + // Выбираем цвета для подсистем (если цветов не хватает начинаем сначала) + const coloredData = arrayOrDefault(data).map((d, i) => ({ ...d, color: subsystemColors[i % subsystemColors.length] })) + + setData(coloredData) + setSelected(data.map((d) => d.idSubsystem)) // По-умолчанию выбираем все подсистемы + }, + setShowLoader, + `Не удалось загрузить данные`, + { actionName: 'Получение данных по скважине', well } + ) + }, [dateRange, well]) + + return ( + +
+

Фильтр подсистем

+
+ d.subsystemName)} - onChange={selectChange} - style={{ width: '100%' }} - > - {childrenData} - - - - setDateRange(dateRange)} - value={[dateRange[0], dateRange[1]]} - /> - - -
- ({name: item.subsystemName, percent: item.kUsage * 100}))} - colors={subsystemColors} - width={'100%'} - height={'50vh'} - /> -
- ({...d, color: subsystemColors[i]}))} - scroll={{ y: '25vh', x: true }} - pagination={false} - /> - - ) -} - -export default wrapPrivateComponent(OperationTime, { - requirements: [], - title: 'Наработка', - route: 'operation_time', -}) \ No newline at end of file diff --git a/src/styles/d3.less b/src/styles/d3.less index 2e48ca4..90db40d 100644 --- a/src/styles/d3.less +++ b/src/styles/d3.less @@ -116,9 +116,9 @@ } } -.grid-line line { +.grid-line:not(:first-of-type):not(:last-of-type) line { stroke: #ddd; - stroke-dasharray: 4 + stroke-dasharray: 4; } @media (max-width: 1800px) { diff --git a/src/styles/filter.less b/src/styles/filter.less new file mode 100644 index 0000000..16618cc --- /dev/null +++ b/src/styles/filter.less @@ -0,0 +1,22 @@ +.filter-group { + margin: 0 0 5px 0; + + & .head { + margin: 5px auto; + align-items: center; + } + + & .body { + width: 100%; + display: flex; + gap: 5px; + + & .type-filter { + width: 25%; + } + + & .filter-selector { + flex: 1; + } + } +} diff --git a/src/styles/message.less b/src/styles/message.less index 513d06f..be78867 100644 --- a/src/styles/message.less +++ b/src/styles/message.less @@ -39,29 +39,6 @@ background: #505060; } -.filter-group { - margin: 0 0 5px 0; - - & .head { - margin: 5px auto; - align-items: center; - } - - & .body { - width: 100%; - display: flex; - gap: 5px; - - & .type-filter { - width: 25%; - } - - & .filter-selector { - flex: 1; - } - } -} - td.ant-table-column-sort { color: black; background-color: #fafafa; diff --git a/src/styles/operation_time.less b/src/styles/operation_time.less new file mode 100644 index 0000000..d35e54f --- /dev/null +++ b/src/styles/operation_time.less @@ -0,0 +1,3 @@ +.table_color { + padding: 5px 0; +}