From c8050b91e55a0b2c06deff7248e4d2806bbedee0 Mon Sep 17 00:00:00 2001 From: goodmice Date: Tue, 23 Aug 2022 17:44:02 +0500 Subject: [PATCH 01/17] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=BE=20=D0=BD=D0=B0=D0=BB=D0=BE=D0=B6=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=82=D0=B5=D0=BB=D0=B5=D0=BC=D0=B5=D1=82?= =?UTF-8?q?=D1=80=D0=B8=D0=B9=20=D0=BF=D1=80=D0=B8=20=D1=81=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=20=D1=81=D0=BA=D0=B2=D0=B0=D0=B6=D0=B8=D0=BD=D1=8B?= =?UTF-8?q?=20*=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=BE?= =?UTF-8?q?=20=D0=BE=D1=82=D0=BE=D0=B1=D1=80=D0=B0=D0=B6=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=B7=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=B3=D1=80=D0=B0=D1=84=D0=B8=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/factory.tsx | 29 +++++++++++++-------- src/pages/Telemetry/TelemetryView/index.jsx | 12 ++++++--- src/pages/Well.jsx | 4 ++- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/components/factory.tsx b/src/components/factory.tsx index 80ad3aa..66efdcf 100644 --- a/src/components/factory.tsx +++ b/src/components/factory.tsx @@ -53,7 +53,7 @@ export const copyToClipboard = (value: string, successText?: string, errorText?: } } -type asyncFunction = (...args: any) => Promise +type asyncFunction = (signal: AbortSignal, ...args: any) => Promise type InvokeOptions = { actionName?: string, @@ -75,23 +75,30 @@ const parseApiEror = (err: unknown, options?: InvokeOptions) => { } } -export const invokeWebApiWrapperAsync = async ( +export const invokeWebApiWrapperAsync = ( funcAsync: asyncFunction, setShowLoader?: Dispatch>, errorNotifyText?: FunctionalValue<(err: unknown) => ReactNode>, options?: InvokeOptions, ) => { + const controller = new AbortController() + const signal = controller.signal + setShowLoader?.(true) - try{ - await funcAsync() - } catch (ex) { - if(isDev()) - console.error(ex) - if (!parseApiEror(ex, options)) + funcAsync(signal) + .then((data) => { + if (data !== false) + setShowLoader?.(false) + }) + .catch((ex) => { + setShowLoader?.(false) + if(isDev()) + console.error(ex) + if (parseApiEror(ex, options)) return notify(getFunctionalValue(errorNotifyText)(ex), 'error', options?.well) - } finally { - setShowLoader?.(false) - } + }) + + return () => controller.abort() } export const download = async (url: string, fileName?: string) => { diff --git a/src/pages/Telemetry/TelemetryView/index.jsx b/src/pages/Telemetry/TelemetryView/index.jsx index c0c0242..3b37f3b 100755 --- a/src/pages/Telemetry/TelemetryView/index.jsx +++ b/src/pages/Telemetry/TelemetryView/index.jsx @@ -143,6 +143,7 @@ const TelemetryView = memo(() => { const [dataSpin, setDataSpin] = useState([]) const [chartInterval, setChartInterval] = useState(defaultPeriod) const [showLoader, setShowLoader] = useState(false) + const [isDataLoading, setIsDataLoading] = useState(false) const [flowChartData, setFlowChartData] = useState([]) const [rop, setRop] = useState(null) const [domain, setDomain] = useState({}) @@ -183,19 +184,23 @@ const TelemetryView = memo(() => { }, [spinSubject$]) useEffect(() => { - invokeWebApiWrapperAsync( - async () => { + const cancel = invokeWebApiWrapperAsync( + async (signal) => { + if (signal.aborted) return false const flowChart = await DrillFlowChartService.getByIdWell(well.id) const dataSaub = await TelemetryDataSaubService.getData(well.id, null, chartInterval) const dataSpin = await TelemetryDataSpinService.getData(well.id, null, chartInterval) + if (signal.aborted) return false setFlowChartData(flowChart ?? []) handleDataSaub(dataSaub) handleDataSpin(dataSpin) }, - null, + setIsDataLoading, `Не удалось получить данные`, { actionName: 'Получение данных по скважине', well } ) + + return () => cancel() }, [well, chartInterval, handleDataSpin, handleDataSaub]) useEffect(() => { @@ -282,6 +287,7 @@ const TelemetryView = memo(() => { { { actionName: 'Изменение данных скважины', well } ), [well]) + const wellContext = useMemo(() => [well, updateWell], [well, updateWell]) + return ( @@ -70,7 +72,7 @@ const Well = memo(() => { } /> - + From bd7c2842c584b02ecea72999e9ee34ed47002416 Mon Sep 17 00:00:00 2001 From: goodmice Date: Mon, 12 Sep 2022 12:40:59 +0500 Subject: [PATCH 02/17] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0?= =?UTF-8?q?=20=D0=BE=D1=87=D0=B8=D1=81=D1=82=D0=BA=D0=B8=20=D0=BE=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D0=B9=20=D0=BF=D0=B5=D1=80=D0=B5?= =?UTF-8?q?=D0=B4=20=D0=B8=D0=BC=D0=BF=D0=BE=D1=80=D1=82=D0=BE=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/WellOperations/ImportOperations.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/WellOperations/ImportOperations.jsx b/src/pages/WellOperations/ImportOperations.jsx index cc0062b..304be1a 100755 --- a/src/pages/WellOperations/ImportOperations.jsx +++ b/src/pages/WellOperations/ImportOperations.jsx @@ -6,7 +6,7 @@ import { ErrorFetch } from '@components/ErrorFetch' import { UploadForm } from '@components/UploadForm' const errorTextStyle = { color: 'red', fontWeight: 'bold' } -const uploadFormStyle = { marginTop: '24px' } +const uploadFormStyle = { marginTop: 24 } export const ImportOperations = memo(({ well: givenWell, onDone }) => { const [deleteBeforeImport, setDeleteBeforeImport] = useState(false) @@ -15,7 +15,7 @@ export const ImportOperations = memo(({ well: givenWell, onDone }) => { const [wellContext] = useWell() const well = useMemo(() => givenWell ?? wellContext, [givenWell, wellContext]) - const url = useMemo(() => `/api/well/${well.id}/wellOperations/import${deleteBeforeImport ? '/1' : '/0'}`, [well]) + const url = useMemo(() => `/api/well/${well.id}/wellOperations/import/${deleteBeforeImport ? 1 : 0}`, [well, deleteBeforeImport]) const onUploadSuccess = useCallback(() => { setErrorText('') From eb8cf1f1d425b238396567f4004f34f06c325c28 Mon Sep 17 00:00:00 2001 From: goodmice Date: Mon, 12 Sep 2022 13:21:37 +0500 Subject: [PATCH 03/17] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=BE=20=D0=BD=D0=B0=D0=B7=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5?= =?UTF-8?q?=20=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86=D1=8B=20=D0=B8=20?= =?UTF-8?q?=D0=BB=D0=BE=D0=B3=D0=BE=D1=82=D0=B8=D0=BF=20=D0=B2=20=D1=88?= =?UTF-8?q?=D0=B0=D0=BF=D0=BA=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/index.html | 2 +- src/images/Logo.tsx | 8 +++++--- src/images/dd_logo_white_opt.svg | 1 + src/styles/App.less | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) create mode 100644 src/images/dd_logo_white_opt.svg diff --git a/public/index.html b/public/index.html index cd94b2e..492d903 100755 --- a/public/index.html +++ b/public/index.html @@ -8,7 +8,7 @@ - АСБ Vision + DDrilling diff --git a/src/images/Logo.tsx b/src/images/Logo.tsx index 88e8540..216a81b 100755 --- a/src/images/Logo.tsx +++ b/src/images/Logo.tsx @@ -1,9 +1,11 @@ import { memo } from 'react' -import logo from '@images/logo_32.png' +import { ReactComponent as AsbLogo } from '@images/dd_logo_white_opt.svg' -export const Logo = memo, HTMLImageElement>>((props) => ( - {'АСБ'} +export type LogoProps = React.SVGProps & { size?: number } + +export const Logo = memo(({ size = 200, ...props }) => ( + )) export default Logo diff --git a/src/images/dd_logo_white_opt.svg b/src/images/dd_logo_white_opt.svg new file mode 100644 index 0000000..d19dc00 --- /dev/null +++ b/src/images/dd_logo_white_opt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/styles/App.less b/src/styles/App.less index cc55b30..0b8e681 100755 --- a/src/styles/App.less +++ b/src/styles/App.less @@ -74,7 +74,7 @@ html { .header .title{ flex-grow: 1; color: #fff; - padding-left: 450px; + padding-left: calc(100vw / 2 - 400px); } .header button{ From 1a4189901aa23e7067b8de5cf202c217ce38534f Mon Sep 17 00:00:00 2001 From: ts_salikhov Date: Mon, 17 Oct 2022 16:59:45 +0400 Subject: [PATCH 04/17] =?UTF-8?q?=D0=9D=D0=B0=20=D1=81=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=86=D0=B5=20=D1=81=D0=BA=D0=B0=D1=87=D0=B8=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=8F=20=D1=84=D0=B0=D0=B9=D0=BB=D0=B0=20?= =?UTF-8?q?=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=BE=20?= =?UTF-8?q?=D0=BD=D0=B0=D0=B7=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D1=84=D0=B0?= =?UTF-8?q?=D0=B9=D0=BB=D0=B0=20=D0=B8=20=D0=BF=D0=B5=D1=80=D0=B5=D1=85?= =?UTF-8?q?=D0=BE=D0=B4=20=D0=BD=D0=B0=20=D0=BF=D1=80=D0=B5=D0=B4=D1=8B?= =?UTF-8?q?=D0=B4=D1=83=D1=89=D1=83=D1=8E=20=D1=81=D1=82=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=86=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/FileDownload.jsx | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/pages/FileDownload.jsx b/src/pages/FileDownload.jsx index c18b51c..9995ae9 100644 --- a/src/pages/FileDownload.jsx +++ b/src/pages/FileDownload.jsx @@ -1,4 +1,4 @@ -import { Link, useNavigate, useParams } from 'react-router-dom' +import { Link, useLocation, useNavigate, useParams } from 'react-router-dom' import { memo, useCallback, useEffect, useState } from 'react' import { InfoCircleFilled, CloseCircleOutlined } from '@ant-design/icons' import { Button, Result, Typography } from 'antd' @@ -20,6 +20,8 @@ const FileDownload = memo(function FileDownload() { const [isError, setIsError] = useState(false) const navigate = useNavigate() + const location = useLocation() + const isFirstOpenApp = location.key === 'default' useEffect(() => { invokeWebApiWrapperAsync( @@ -33,10 +35,8 @@ const FileDownload = memo(function FileDownload() { useEffect(() => { invokeWebApiWrapperAsync( async () => { - const files = await FileService.getFilesInfo(idWell) - // TODO Получается только одна категория файлов. - // Поменять при появлении метода получения инфы о конкретном файле - setFile(files.items.find((file) => file.id === idFile) ?? { id: idFile, idWell, name: `File_${idWell}_${idFile}` }) + const file = await FileService.getFileInfo(idFile) + setFile(file) }, null, () => { @@ -48,7 +48,7 @@ const FileDownload = memo(function FileDownload() { }, [idWell, idFile]) const download = useCallback(async () => { - if (!await downloadFile(file)) + if (!file || !await downloadFile(file)) setIsError(true) }, [file]) @@ -60,13 +60,16 @@ const FileDownload = memo(function FileDownload() { <> Вы перешли к странице загрузки файла!
- Файл "{file.name ?? ('№' + idFile)}", скважина "{well.caption ?? ('№' + idWell)}". + Файл "{file?.name ?? ('№' + idFile)}", скважина "{well.caption ?? ('№' + idWell)}". )} // subTitle={} extra={( <> - + {isFirstOpenApp + ? + : + } )} From 53a1d33a5503cced37e75402430432711820d73d Mon Sep 17 00:00:00 2001 From: ts_salikhov Date: Mon, 17 Oct 2022 17:19:13 +0400 Subject: [PATCH 05/17] =?UTF-8?q?=D0=9D=D0=B0=20=D1=81=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D1=86=D0=B5=20=D1=81=D0=BA=D0=B0=D1=87=D0=B8=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=8F=20=D1=84=D0=B0=D0=B9=D0=BB=D0=B0=20?= =?UTF-8?q?=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=BE=20?= =?UTF-8?q?=D0=BD=D0=B0=D0=B7=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D1=84=D0=B0?= =?UTF-8?q?=D0=B9=D0=BB=D0=B0=20=D0=B8=20=D0=BF=D0=B5=D1=80=D0=B5=D1=85?= =?UTF-8?q?=D0=BE=D0=B4=20=D0=BD=D0=B0=20=D0=BF=D1=80=D0=B5=D0=B4=D1=8B?= =?UTF-8?q?=D0=B4=D1=83=D1=89=D1=83=D1=8E=20=D1=81=D1=82=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=86=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/FileDownload.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/FileDownload.jsx b/src/pages/FileDownload.jsx index 9995ae9..496826b 100644 --- a/src/pages/FileDownload.jsx +++ b/src/pages/FileDownload.jsx @@ -1,5 +1,5 @@ import { Link, useLocation, useNavigate, useParams } from 'react-router-dom' -import { memo, useCallback, useEffect, useState } from 'react' +import { memo, useCallback, useEffect, useMemo, useState } from 'react' import { InfoCircleFilled, CloseCircleOutlined } from '@ant-design/icons' import { Button, Result, Typography } from 'antd' @@ -21,7 +21,7 @@ const FileDownload = memo(function FileDownload() { const navigate = useNavigate() const location = useLocation() - const isFirstOpenApp = location.key === 'default' + const isFirstOpenApp = useMemo(() => location.key === 'default', [location]) useEffect(() => { invokeWebApiWrapperAsync( @@ -45,7 +45,7 @@ const FileDownload = memo(function FileDownload() { }, { actionName: 'Получение информации о файле' } ) - }, [idWell, idFile]) + }, [idFile]) const download = useCallback(async () => { if (!file || !await downloadFile(file)) From 5dd1fc8258d3c1a3805a713c7bcddf30ab19eb2e Mon Sep 17 00:00:00 2001 From: ts_salikhov Date: Wed, 19 Oct 2022 15:19:19 +0400 Subject: [PATCH 06/17] =?UTF-8?q?=D0=A3=D0=B1=D1=80=D0=B0=D0=BD=D0=B0=20?= =?UTF-8?q?=D0=B8=D0=BD=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=86=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=BE=D0=B1=20id=20=D1=81=D0=BA=D0=B2=D0=B0=D0=B6=D0=B8=D0=BD?= =?UTF-8?q?=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/FileDownload.jsx | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/pages/FileDownload.jsx b/src/pages/FileDownload.jsx index 496826b..810894e 100644 --- a/src/pages/FileDownload.jsx +++ b/src/pages/FileDownload.jsx @@ -5,17 +5,16 @@ import { Button, Result, Typography } from 'antd' import { downloadFile, invokeWebApiWrapperAsync } from '@components/factory' import { wrapPrivateComponent } from '@utils' -import { FileService, WellService } from '@api' +import { FileService } from '@api' import AccessDenied from './AccessDenied' const { Paragraph, Text } = Typography -export const getLinkToFile = (fileInfo) => `/file_download/${fileInfo.idWell}/${fileInfo.id}` +export const getLinkToFile = (fileInfo) => `/file_download/${fileInfo.id}` const FileDownload = memo(function FileDownload() { - const { idWell, idFile } = useParams() - const [well, setWell] = useState({}) + const { idFile } = useParams() const [file, setFile] = useState({}) const [isError, setIsError] = useState(false) @@ -23,15 +22,6 @@ const FileDownload = memo(function FileDownload() { const location = useLocation() const isFirstOpenApp = useMemo(() => location.key === 'default', [location]) - useEffect(() => { - invokeWebApiWrapperAsync( - async () => setWell(await WellService.get(idWell)), - null, - 'Не удалось получить информацию о скважине', - { actionName: 'Получение данных о скважине' } - ) - }, [idWell]) - useEffect(() => { invokeWebApiWrapperAsync( async () => { @@ -60,7 +50,7 @@ const FileDownload = memo(function FileDownload() { <> Вы перешли к странице загрузки файла!
- Файл "{file?.name ?? ('№' + idFile)}", скважина "{well.caption ?? ('№' + idWell)}". + Файл "{file?.name ?? ('№' + idFile)}". )} // subTitle={} @@ -106,5 +96,5 @@ FileDownload.displayName = 'FileDownloadMemo' export default wrapPrivateComponent(FileDownload, { requirements: ['File.get'], - route: 'file_download/:idWell/:idFile/*', + route: 'file_download/:idFile/*', }, ) From ccbc0e1938be1f3a8bb2ca6b2b2a8ef409dcdcb8 Mon Sep 17 00:00:00 2001 From: ts_salikhov Date: Thu, 27 Oct 2022 10:35:32 +0400 Subject: [PATCH 07/17] =?UTF-8?q?=D0=9E=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D1=80=D0=BE=D1=83=D1=82=20=D0=B4=D0=BB=D1=8F=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=BC=D0=BF=D0=BE=D0=BD=D0=B5=D0=BD=D1=82=D0=B0=20?= =?UTF-8?q?FileDownload?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App.tsx b/src/App.tsx index 7498b86..0ac3eb0 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -42,7 +42,7 @@ export const App = memo(() => ( {/* User pages */} }> - } /> + } /> }> {/* Admin pages */} From c8753378eb48ed93164c1bb0161dbda61fb8a664 Mon Sep 17 00:00:00 2001 From: goodmice Date: Mon, 31 Oct 2022 05:10:28 +0500 Subject: [PATCH 08/17] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B0?= =?UTF-8?q?=20=D0=B2=20=D0=BD=D0=B0=D0=B7=D0=BD=D0=B0=D1=87=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B8=20Breadcrumb.Item?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/LayoutPortal.tsx | 2 +- src/components/MenuBreadcrumb.tsx | 58 +++++++++++++------------------ src/pages/AdminPanel/index.jsx | 25 +++++++------ src/pages/Well/index.jsx | 6 ++-- 4 files changed, 42 insertions(+), 49 deletions(-) diff --git a/src/components/LayoutPortal.tsx b/src/components/LayoutPortal.tsx index 97173e3..c8c3f0b 100644 --- a/src/components/LayoutPortal.tsx +++ b/src/components/LayoutPortal.tsx @@ -114,7 +114,7 @@ const _LayoutPortal = memo(() => { setWellsTreeOpen((prev) => !prev)}>{currentWell} )} - {breadcrumb} + {breadcrumb !== true && breadcrumb} )} {topRightBlock} diff --git a/src/components/MenuBreadcrumb.tsx b/src/components/MenuBreadcrumb.tsx index 05cbc74..5299039 100644 --- a/src/components/MenuBreadcrumb.tsx +++ b/src/components/MenuBreadcrumb.tsx @@ -1,10 +1,9 @@ import { Breadcrumb, BreadcrumbItemProps } from 'antd' -import { Link, useLocation } from 'react-router-dom' -import { memo, useMemo } from 'react' +import { Link } from 'react-router-dom' import { join } from 'path' import { PrivateWellMenuItem } from '@components/PrivateWellMenu' -import { FunctionalValue, useFunctionalValue } from '@utils' +import { FunctionalValue, getFunctionalValue, } from '@utils' export const makeBreadcrumbItems = (items: PrivateWellMenuItem[], pathParts: string[], root: string = '/') => { const out = [] @@ -22,35 +21,26 @@ export const makeBreadcrumbItems = (items: PrivateWellMenuItem[], pathParts: str return out } -export type MenuBreadcrumbItemsProps = { - menuItems: PrivateWellMenuItem[] - pathRoot?: RegExp - itemsProps?: FunctionalValue<(item: PrivateWellMenuItem) => BreadcrumbItemProps> - itemRender?: (item: PrivateWellMenuItem) => JSX.Element +export const makeMenuBreadcrumbItems = ( + menuItems: PrivateWellMenuItem[], + path: string, + pathRoot: RegExp = /^\//, + itemsProps?: FunctionalValue<(item: PrivateWellMenuItem) => BreadcrumbItemProps>, + itemRender?: (item: PrivateWellMenuItem) => JSX.Element, +) => { + const getItemProps = getFunctionalValue(itemsProps) + + const rootPart = pathRoot.exec(path) + if (!rootPart || rootPart.length <= 0) return [] + const root = rootPart[0] + const parts = path.trim().slice(root.length).split('/') + const items = makeBreadcrumbItems(menuItems, parts, root) + + return items.map((item) => ( + + {itemRender ? itemRender(item) : ( + {item.title} + )} + + )) } - -export const MenuBreadcrumbItems = memo(({ menuItems, pathRoot = /^\//, itemsProps, itemRender }) => { - const location = useLocation() - const getItemProps = useFunctionalValue(itemsProps) - - const items = useMemo(() => { - const path = location.pathname - const rootPart = pathRoot.exec(path) - if (!rootPart || rootPart.length <= 0) return [] - const root = rootPart[0] - const parts = path.trim().slice(root.length).split('/') - return makeBreadcrumbItems(menuItems, parts, root) - }, [location, menuItems, pathRoot]) - - return ( - <> - {items.map((item) => ( - - {itemRender ? itemRender(item) : ( - {item.title} - )} - - ))} - - ) -}) diff --git a/src/pages/AdminPanel/index.jsx b/src/pages/AdminPanel/index.jsx index ad338e2..e4c11b8 100755 --- a/src/pages/AdminPanel/index.jsx +++ b/src/pages/AdminPanel/index.jsx @@ -1,9 +1,9 @@ -import { Navigate, Route, Routes } from 'react-router-dom' -import { lazy, memo, useMemo } from 'react' +import { Navigate, Route, Routes, useLocation } from 'react-router-dom' +import { lazy, memo, useEffect, useMemo } from 'react' import { RootPathContext, useLayoutProps, useRootPath } from '@asb/context' import { FastRunMenu } from '@components/FastRunMenu' -import { MenuBreadcrumbItems } from '@components/MenuBreadcrumb' +import { makeMenuBreadcrumbItems } from '@components/MenuBreadcrumb' import { NoAccessComponent, withPermissions } from '@utils' import { AdminNavigationMenu, menuItems } from './AdminNavigationMenu' @@ -21,18 +21,21 @@ const TelemetryViewer = lazy(() => import('./Telemetry/TelemetryViewer')) const TelemetryMerger = lazy(() => import('./Telemetry/TelemetryMerger')) const VisitLog = lazy(() => import('./VisitLog')) -const layoutProps = { - sider: , - title: 'Администраторская панель', - isAdmin: true, - breadcrumb: , -} - const AdminPanel = memo(() => { + const location = useLocation() const root = useRootPath() const rootPath = useMemo(() => `${root}/admin`, [root]) - useLayoutProps(layoutProps) + const setLayoutProps = useLayoutProps() + + useEffect(() => { + setLayoutProps({ + sider: , + title: 'Администраторская панель', + isAdmin: true, + breadcrumb: makeMenuBreadcrumbItems(menuItems, location.pathname, /^\/admin\//), + }) + }, [location.pathname]) return ( diff --git a/src/pages/Well/index.jsx b/src/pages/Well/index.jsx index 534b313..398a0b8 100644 --- a/src/pages/Well/index.jsx +++ b/src/pages/Well/index.jsx @@ -4,7 +4,7 @@ import { Navigate, Route, Routes, useLocation, useParams } from 'react-router-do import { WellContext, RootPathContext, useRootPath, useLayoutProps, TopRightBlockContext } from '@asb/context' import { FastRunMenu } from '@components/FastRunMenu' import { invokeWebApiWrapperAsync } from '@components/factory' -import { MenuBreadcrumbItems } from '@components/MenuBreadcrumb' +import { makeMenuBreadcrumbItems } from '@components/MenuBreadcrumb' import { NoAccessComponent, withPermissions } from '@utils' import { WellService } from '@api' @@ -78,9 +78,9 @@ const Well = memo(() => { useEffect(() => setLayoutProps({ sider: , - breadcrumb: , + breadcrumb: makeMenuBreadcrumbItems(menuItems, location.pathname, /^\/well\/[0-9]+\//), topRightBlock: topRightBlock, - }), [well, setLayoutProps, topRightBlock]) + }), [well, location.pathname, setLayoutProps, topRightBlock]) useEffect(() => setTopRightBlock(undefined), [location]) From 45c63317a2f6ff5806a1d7a456c6e9b44510867e Mon Sep 17 00:00:00 2001 From: goodmice Date: Mon, 31 Oct 2022 13:52:33 +0500 Subject: [PATCH 09/17] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B0?= =?UTF-8?q?=20=D1=84=D0=B8=D0=BB=D1=8C=D1=82=D1=80=D0=B0=D1=86=D0=B8=D0=B8?= =?UTF-8?q?=20=D1=81=D1=83=D1=82=D0=BE=D1=87=D0=BD=D1=8B=D1=85=20=D1=80?= =?UTF-8?q?=D0=B0=D0=BF=D0=BE=D1=80=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Well/Reports/DailyReport/index.jsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/Well/Reports/DailyReport/index.jsx b/src/pages/Well/Reports/DailyReport/index.jsx index aa19d13..0c303b1 100644 --- a/src/pages/Well/Reports/DailyReport/index.jsx +++ b/src/pages/Well/Reports/DailyReport/index.jsx @@ -72,8 +72,7 @@ const DailyReport = memo(() => { const filteredData = useMemo(() => { if (!searchDate) return data - const endDate = moment(searchDate[1]).add(1, 'd') - return data.filter((row) => moment(row.reportDate).isBetween(searchDate[0], endDate, 'ms', '[)')) + return data.filter((row) => moment(row.reportDate).isBetween(searchDate[0], searchDate[1], 'day', '[]')) }, [data, searchDate]) return ( From 683ccb1c034b080e9f2e72a585bd63104611af3e Mon Sep 17 00:00:00 2001 From: goodmice Date: Sat, 5 Nov 2022 03:20:21 +0500 Subject: [PATCH 10/17] =?UTF-8?q?web-vitals=20=D1=83=D0=B4=D0=B0=D0=BB?= =?UTF-8?q?=D1=91=D0=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 13 +------------ src/react-app-env.d.ts | 1 - src/reportWebVitals.ts | 12 ------------ 3 files changed, 1 insertion(+), 25 deletions(-) delete mode 100755 src/react-app-env.d.ts delete mode 100644 src/reportWebVitals.ts diff --git a/package-lock.json b/package-lock.json index 3cf958f..8912fac 100755 --- a/package-lock.json +++ b/package-lock.json @@ -17,8 +17,7 @@ "react-dom": "^18.1.0", "react-router-dom": "^6.3.0", "rxjs": "^7.5.5", - "usehooks-ts": "^2.6.0", - "web-vitals": "^2.1.4" + "usehooks-ts": "^2.6.0" }, "devDependencies": { "@babel/core": "^7.18.2", @@ -14786,11 +14785,6 @@ "minimalistic-assert": "^1.0.0" } }, - "node_modules/web-vitals": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-2.1.4.tgz", - "integrity": "sha512-sVWcwhU5mX6crfI5Vd2dC4qchyTqxV8URinzt25XqVh+bHEPGH4C3NPrNionCP7Obx59wrYEbNlw4Z8sjALzZg==" - }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -26492,11 +26486,6 @@ "minimalistic-assert": "^1.0.0" } }, - "web-vitals": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-2.1.4.tgz", - "integrity": "sha512-sVWcwhU5mX6crfI5Vd2dC4qchyTqxV8URinzt25XqVh+bHEPGH4C3NPrNionCP7Obx59wrYEbNlw4Z8sjALzZg==" - }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts deleted file mode 100755 index 6431bc5..0000000 --- a/src/react-app-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// diff --git a/src/reportWebVitals.ts b/src/reportWebVitals.ts deleted file mode 100644 index 30e6a9d..0000000 --- a/src/reportWebVitals.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { getCLS, getFID, getFCP, getLCP, getTTFB, ReportHandler } from 'web-vitals' - -export const reportWebVitals = (onPerfEntry?: ReportHandler) => { - if (!onPerfEntry) return - getCLS(onPerfEntry) - getFID(onPerfEntry) - getFCP(onPerfEntry) - getLCP(onPerfEntry) - getTTFB(onPerfEntry) -} - -export default reportWebVitals From bf2d6d6d361ee8c73f8c7570b848b9e56b85a115 Mon Sep 17 00:00:00 2001 From: goodmice Date: Mon, 7 Nov 2022 05:38:31 +0500 Subject: [PATCH 11/17] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B0?= =?UTF-8?q?=20=D0=BD=D0=B0=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?=D1=82=D0=B5=D0=BB=D0=B5=D0=BC=D0=B5=D1=82=D1=80=D0=B8=D0=B9=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B8=20=D0=B0=D0=BA=D1=82=D0=B8=D0=B2=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D1=81=D0=BA=D0=B2=D0=B0=D0=B6=D0=B8=D0=BD=D0=B0=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Well/Telemetry/TelemetryView/index.jsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/pages/Well/Telemetry/TelemetryView/index.jsx b/src/pages/Well/Telemetry/TelemetryView/index.jsx index 7a2ca50..b2c654f 100644 --- a/src/pages/Well/Telemetry/TelemetryView/index.jsx +++ b/src/pages/Well/Telemetry/TelemetryView/index.jsx @@ -140,6 +140,7 @@ export const normalizeData = (data) => data?.map(item => ({ const dateSorter = makeDateSorter('date') const TelemetryView = memo(() => { + const [currentWellId, setCurrentWellId] = useState(null) const [dataSaub, setDataSaub] = useState([]) const [dataSpin, setDataSpin] = useState([]) const [chartInterval, setChartInterval] = useState(defaultPeriod) @@ -154,11 +155,11 @@ const TelemetryView = memo(() => { const saubSubject$ = useMemo(() => new BehaviorSubject(), []) const spinSubject$ = useMemo(() => new BehaviorSubject(), []) - const handleDataSaub = useCallback((data) => { + const handleDataSaub = useCallback((data, replace = false) => { if (data) { const dataSaub = normalizeData(data) setDataSaub((prev) => { - const out = [...prev, ...dataSaub] + const out = replace ? [...dataSaub] : [...prev, ...dataSaub] out.sort(dateSorter) return out }) @@ -184,20 +185,22 @@ const TelemetryView = memo(() => { }, [spinSubject$]) useEffect(() => { + if (currentWellId == well.id) return + setCurrentWellId(well.id) invokeWebApiWrapperAsync( async () => { const flowChart = await DrillFlowChartService.getByIdWell(well.id) const dataSaub = await TelemetryDataSaubService.getData(well.id, null, chartInterval) const dataSpin = await TelemetryDataSpinService.getData(well.id, null, chartInterval) setFlowChartData(flowChart ?? []) - handleDataSaub(dataSaub) - handleDataSpin(dataSpin) + handleDataSaub(dataSaub, true) + setDataSpin(Array.isArray(dataSpin) ? dataSpin : []) }, null, `Не удалось получить данные`, { actionName: 'Получение данных по скважине', well } ) - }, [well, chartInterval, handleDataSpin, handleDataSaub]) + }, [well, chartInterval, currentWellId, handleDataSaub]) useEffect(() => { const unsubscribe = Subscribe( From 33b6a2012aadf67d3839e9f907652e16d186b492 Mon Sep 17 00:00:00 2001 From: goodmice Date: Mon, 7 Nov 2022 06:33:14 +0500 Subject: [PATCH 12/17] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=B0=D0=BD=D0=BE=20=D0=BE=D1=87=D0=B8=D1=89=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=B3=D1=80=D0=B0=D1=84=D0=B8=D0=BA=D0=B0=20?= =?UTF-8?q?=D1=82=D0=B5=D0=BB=D0=B5=D0=BC=D0=B5=D1=82=D1=80=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Well/Telemetry/TelemetryView/index.jsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/pages/Well/Telemetry/TelemetryView/index.jsx b/src/pages/Well/Telemetry/TelemetryView/index.jsx index b2c654f..0587474 100644 --- a/src/pages/Well/Telemetry/TelemetryView/index.jsx +++ b/src/pages/Well/Telemetry/TelemetryView/index.jsx @@ -156,14 +156,14 @@ const TelemetryView = memo(() => { const spinSubject$ = useMemo(() => new BehaviorSubject(), []) const handleDataSaub = useCallback((data, replace = false) => { - if (data) { + setDataSaub((prev) => { + if (!data) + return replace ? [] : prev const dataSaub = normalizeData(data) - setDataSaub((prev) => { - const out = replace ? [...dataSaub] : [...prev, ...dataSaub] - out.sort(dateSorter) - return out - }) - } + const out = replace ? [...dataSaub] : [...prev, ...dataSaub] + out.sort(dateSorter) + return out + }) }, []) const handleDataSpin = useCallback((data) => data && setDataSpin((prev) => [...prev, ...data]), []) From 9c85b1e22922fce37dbd35fa7348ae7a95199ce2 Mon Sep 17 00:00:00 2001 From: goodmice Date: Mon, 7 Nov 2022 05:38:31 +0500 Subject: [PATCH 13/17] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B0?= =?UTF-8?q?=20=D0=BD=D0=B0=D0=BB=D0=BE=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?=D1=82=D0=B5=D0=BB=D0=B5=D0=BC=D0=B5=D1=82=D1=80=D0=B8=D0=B9=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B8=20=D0=B0=D0=BA=D1=82=D0=B8=D0=B2=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D1=81=D0=BA=D0=B2=D0=B0=D0=B6=D0=B8=D0=BD=D0=B0=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Well/Telemetry/TelemetryView/index.jsx | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/pages/Well/Telemetry/TelemetryView/index.jsx b/src/pages/Well/Telemetry/TelemetryView/index.jsx index 35efc86..fd17199 100644 --- a/src/pages/Well/Telemetry/TelemetryView/index.jsx +++ b/src/pages/Well/Telemetry/TelemetryView/index.jsx @@ -140,6 +140,7 @@ export const normalizeData = (data) => data?.map(item => ({ const dateSorter = makeDateSorter('date') const TelemetryView = memo(() => { + const [currentWellId, setCurrentWellId] = useState(null) const [dataSaub, setDataSaub] = useState([]) const [dataSpin, setDataSpin] = useState([]) const [chartInterval, setChartInterval] = useState(defaultPeriod) @@ -155,11 +156,11 @@ const TelemetryView = memo(() => { const saubSubject$ = useMemo(() => new BehaviorSubject(), []) const spinSubject$ = useMemo(() => new BehaviorSubject(), []) - const handleDataSaub = useCallback((data) => { + const handleDataSaub = useCallback((data, replace = false) => { if (data) { const dataSaub = normalizeData(data) setDataSaub((prev) => { - const out = [...prev, ...dataSaub] + const out = replace ? [...dataSaub] : [...prev, ...dataSaub] out.sort(dateSorter) return out }) @@ -185,24 +186,23 @@ const TelemetryView = memo(() => { }, [spinSubject$]) useEffect(() => { - const cancel = invokeWebApiWrapperAsync( - async (signal) => { - if (signal.aborted) return false + if (currentWellId == well.id) return + setCurrentWellId(well.id) + invokeWebApiWrapperAsync( + async () => { const flowChart = await DrillFlowChartService.getByIdWell(well.id) const dataSaub = await TelemetryDataSaubService.getData(well.id, null, chartInterval) const dataSpin = await TelemetryDataSpinService.getData(well.id, null, chartInterval) if (signal.aborted) return false setFlowChartData(flowChart ?? []) - handleDataSaub(dataSaub) - handleDataSpin(dataSpin) + handleDataSaub(dataSaub, true) + setDataSpin(Array.isArray(dataSpin) ? dataSpin : []) }, setIsDataLoading, `Не удалось получить данные`, { actionName: 'Получение данных по скважине', well } ) - - return () => cancel() - }, [well, chartInterval, handleDataSpin, handleDataSaub]) + }, [well, chartInterval, currentWellId, handleDataSaub]) useEffect(() => { const unsubscribe = Subscribe( From f82b80d0d0dbbd93a3c3cfc31356f9cdd12622ea Mon Sep 17 00:00:00 2001 From: goodmice Date: Mon, 7 Nov 2022 06:33:14 +0500 Subject: [PATCH 14/17] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=B0=D0=BD=D0=BE=20=D0=BE=D1=87=D0=B8=D1=89=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=B3=D1=80=D0=B0=D1=84=D0=B8=D0=BA=D0=B0=20?= =?UTF-8?q?=D1=82=D0=B5=D0=BB=D0=B5=D0=BC=D0=B5=D1=82=D1=80=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Well/Telemetry/TelemetryView/index.jsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/pages/Well/Telemetry/TelemetryView/index.jsx b/src/pages/Well/Telemetry/TelemetryView/index.jsx index fd17199..4193658 100644 --- a/src/pages/Well/Telemetry/TelemetryView/index.jsx +++ b/src/pages/Well/Telemetry/TelemetryView/index.jsx @@ -157,14 +157,14 @@ const TelemetryView = memo(() => { const spinSubject$ = useMemo(() => new BehaviorSubject(), []) const handleDataSaub = useCallback((data, replace = false) => { - if (data) { + setDataSaub((prev) => { + if (!data) + return replace ? [] : prev const dataSaub = normalizeData(data) - setDataSaub((prev) => { - const out = replace ? [...dataSaub] : [...prev, ...dataSaub] - out.sort(dateSorter) - return out - }) - } + const out = replace ? [...dataSaub] : [...prev, ...dataSaub] + out.sort(dateSorter) + return out + }) }, []) const handleDataSpin = useCallback((data) => data && setDataSpin((prev) => [...prev, ...data]), []) From a04090db572a0edb74ad71c7a03c5589efaf1e9a Mon Sep 17 00:00:00 2001 From: goodmice Date: Mon, 7 Nov 2022 07:12:44 +0500 Subject: [PATCH 15/17] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=BE=20=D0=BD=D0=B0=D0=BB=D0=BE=D0=B6=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=B0=D0=BA=D1=82=D0=B8=D0=B2=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D1=82=D0=B5=D0=BB=D0=B5=D0=BC=D0=B5=D1=82=D1=80=D0=B8?= =?UTF-8?q?=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Well/Telemetry/TelemetryView/index.jsx | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/pages/Well/Telemetry/TelemetryView/index.jsx b/src/pages/Well/Telemetry/TelemetryView/index.jsx index 35efc86..e8c90bb 100644 --- a/src/pages/Well/Telemetry/TelemetryView/index.jsx +++ b/src/pages/Well/Telemetry/TelemetryView/index.jsx @@ -140,6 +140,7 @@ export const normalizeData = (data) => data?.map(item => ({ const dateSorter = makeDateSorter('date') const TelemetryView = memo(() => { + const [currentWellId, setCurrentWellId] = useState(null) const [dataSaub, setDataSaub] = useState([]) const [dataSpin, setDataSpin] = useState([]) const [chartInterval, setChartInterval] = useState(defaultPeriod) @@ -155,15 +156,15 @@ const TelemetryView = memo(() => { const saubSubject$ = useMemo(() => new BehaviorSubject(), []) const spinSubject$ = useMemo(() => new BehaviorSubject(), []) - const handleDataSaub = useCallback((data) => { - if (data) { + const handleDataSaub = useCallback((data, replace = false) => { + setDataSaub((prev) => { + if (!data) + return replace ? [] : prev const dataSaub = normalizeData(data) - setDataSaub((prev) => { - const out = [...prev, ...dataSaub] - out.sort(dateSorter) - return out - }) - } + const out = replace ? [...dataSaub] : [...prev, ...dataSaub] + out.sort(dateSorter) + return out + }) }, []) const handleDataSpin = useCallback((data) => data && setDataSpin((prev) => [...prev, ...data]), []) @@ -185,24 +186,22 @@ const TelemetryView = memo(() => { }, [spinSubject$]) useEffect(() => { - const cancel = invokeWebApiWrapperAsync( - async (signal) => { - if (signal.aborted) return false + if (currentWellId == well.id) return + setCurrentWellId(well.id) + invokeWebApiWrapperAsync( + async () => { const flowChart = await DrillFlowChartService.getByIdWell(well.id) const dataSaub = await TelemetryDataSaubService.getData(well.id, null, chartInterval) const dataSpin = await TelemetryDataSpinService.getData(well.id, null, chartInterval) - if (signal.aborted) return false setFlowChartData(flowChart ?? []) - handleDataSaub(dataSaub) - handleDataSpin(dataSpin) + handleDataSaub(dataSaub, true) + setDataSpin(Array.isArray(dataSpin) ? dataSpin : []) }, setIsDataLoading, `Не удалось получить данные`, { actionName: 'Получение данных по скважине', well } ) - - return () => cancel() - }, [well, chartInterval, handleDataSpin, handleDataSaub]) + }, [well, chartInterval, currentWellId, handleDataSaub]) useEffect(() => { const unsubscribe = Subscribe( From bc734900290ebfcfb31db528c6eba9d6fdc1f715 Mon Sep 17 00:00:00 2001 From: goodmice Date: Tue, 8 Nov 2022 08:03:05 +0500 Subject: [PATCH 16/17] =?UTF-8?q?=D0=97=D0=B0=D0=B2=D0=B8=D1=81=D0=B8?= =?UTF-8?q?=D0=BC=D0=BE=D1=81=D1=82=D1=8C=20Table=20=D0=B7=D0=B0=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=B5=D0=BD=D0=B0=20=D1=81=20antd=20=D0=BD=D0=B0?= =?UTF-8?q?=20@components/Table?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Cluster/WellOperationsTable.jsx | 3 +-- .../Analytics/WellCompositeEditor/WellCompositeSections.jsx | 4 ++-- src/pages/Well/Reports/DailyReport/ReportEditor.jsx | 6 +++--- .../Well/Telemetry/TelemetryView/ActiveMessagesOnline.jsx | 4 ++-- src/pages/Well/WellCase/index.jsx | 2 +- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/pages/Cluster/WellOperationsTable.jsx b/src/pages/Cluster/WellOperationsTable.jsx index 1d2b094..1e8ee65 100755 --- a/src/pages/Cluster/WellOperationsTable.jsx +++ b/src/pages/Cluster/WellOperationsTable.jsx @@ -1,7 +1,6 @@ import { memo, useMemo } from 'react' -import { Table } from 'antd' -import { makeTextColumn, makeNumericColumnPlanFact } from '@components/Table' +import { Table, makeTextColumn, makeNumericColumnPlanFact } from '@components/Table' import { getPrecision } from '@utils/functions' const columns = [ diff --git a/src/pages/Well/Analytics/WellCompositeEditor/WellCompositeSections.jsx b/src/pages/Well/Analytics/WellCompositeEditor/WellCompositeSections.jsx index 426ed21..52931a4 100644 --- a/src/pages/Well/Analytics/WellCompositeEditor/WellCompositeSections.jsx +++ b/src/pages/Well/Analytics/WellCompositeEditor/WellCompositeSections.jsx @@ -1,12 +1,12 @@ import { Link, useLocation } from 'react-router-dom' import { useState, useEffect, memo, useMemo, lazy, Suspense } from 'react' import { LineChartOutlined, ProfileOutlined, TeamOutlined } from '@ant-design/icons' -import { Table, Button, Badge, Divider, Modal, Row, Col } from 'antd' +import { Button, Badge, Divider, Modal, Row, Col } from 'antd' import { useWell } from '@asb/context' import LoaderPortal from '@components/LoaderPortal' import { invokeWebApiWrapperAsync } from '@components/factory' -import { makeTextColumn, makeNumericColumnPlanFact, makeNumericColumn } from '@components/Table' +import { Table, makeTextColumn, makeNumericColumnPlanFact, makeNumericColumn } from '@components/Table' import { WellCompositeService } from '@api' import { hasPermission, diff --git a/src/pages/Well/Reports/DailyReport/ReportEditor.jsx b/src/pages/Well/Reports/DailyReport/ReportEditor.jsx index e77fc61..05c171a 100644 --- a/src/pages/Well/Reports/DailyReport/ReportEditor.jsx +++ b/src/pages/Well/Reports/DailyReport/ReportEditor.jsx @@ -1,15 +1,15 @@ -import { DatePicker, Descriptions, Form, Input, InputNumber, Modal, Table, Tabs } from 'antd' +import { DatePicker, Descriptions, Form, Input, InputNumber, Modal, Table as RawTable, Tabs } from 'antd' import { memo, useCallback, useEffect, useState } from 'react' import moment from 'moment' import { useWell } from '@asb/context' import LoaderPortal from '@components/LoaderPortal' import { invokeWebApiWrapperAsync } from '@components/factory' -import { makeColumn, makeGroupColumn } from '@components/Table' +import { Table, makeColumn, makeGroupColumn } from '@components/Table' import { DailyReportService } from '@api' const { Item: RawItem } = Form -const { Summary } = Table +const { Summary } = RawTable const { TabPane } = Tabs const Item = memo(({ style, ...other }) => ) diff --git a/src/pages/Well/Telemetry/TelemetryView/ActiveMessagesOnline.jsx b/src/pages/Well/Telemetry/TelemetryView/ActiveMessagesOnline.jsx index 910aac7..dbe5af1 100644 --- a/src/pages/Well/Telemetry/TelemetryView/ActiveMessagesOnline.jsx +++ b/src/pages/Well/Telemetry/TelemetryView/ActiveMessagesOnline.jsx @@ -1,7 +1,7 @@ -import { Table } from 'antd' import { useState, useEffect, useCallback, memo, useMemo } from 'react' import { useWell } from '@asb/context' +import { Table } from '@components/Table' import LoaderPortal from '@components/LoaderPortal' import { invokeWebApiWrapperAsync } from '@components/factory' import { Subscribe } from '@services/signalr' @@ -22,7 +22,7 @@ export const ActiveMessagesOnline = memo(({ well: givenWell }) => { if (messages) setMessages(messages.items.splice(0, 4)) }, []) - + const columns = useMemo(() => makeMessageColumns(well.id), [well.id]) useEffect(() => { diff --git a/src/pages/Well/WellCase/index.jsx b/src/pages/Well/WellCase/index.jsx index 3912da6..1eb9709 100644 --- a/src/pages/Well/WellCase/index.jsx +++ b/src/pages/Well/WellCase/index.jsx @@ -1,5 +1,5 @@ import { memo, useCallback, useEffect, useMemo, useState } from 'react' -import { Alert, Button, Typography } from 'antd' +import { Alert, Button } from 'antd' import { useWell } from '@asb/context' import { UserView } from '@components/views' From aa0fafb7a1e3e9b5a883e39a33dd9ec99fe47cc4 Mon Sep 17 00:00:00 2001 From: goodmice Date: Tue, 8 Nov 2022 08:09:22 +0500 Subject: [PATCH 17/17] =?UTF-8?q?*=20EditableCell=20=D1=83=D0=BB=D1=83?= =?UTF-8?q?=D1=87=D1=88=D0=B5=D0=BD=D0=B0=20=D0=BC=D0=B5=D0=BC=D0=BE=D0=B8?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20*=20=D0=94=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5?= =?UTF-8?q?=D1=80=D0=B6=D0=BA=D0=B0=20=D1=81=D0=BE=D1=81=D1=82=D0=B0=D0=B2?= =?UTF-8?q?=D0=BD=D1=8B=D1=85=20=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=B9=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D1=81=D1=82=D0=BE=D0=BB=D0=B1=D1=86=D0=BE?= =?UTF-8?q?=D0=B2=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=20*=20=D0=A3?= =?UTF-8?q?=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD=D0=B0=20=D1=82=D0=B8=D0=BF?= =?UTF-8?q?=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F=20*=20=D0=9C=D0=B5=D1=82?= =?UTF-8?q?=D0=BE=D0=B4=D1=8B-=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D1=8B=20=D1=81=D1=82=D0=BE=D0=BB=D0=B1=D1=86=D0=BE?= =?UTF-8?q?=D0=B2=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BF=D0=B8=D1=81=D0=B0=D0=BD?= =?UTF-8?q?=D1=8B=20*=20=D0=9C=D0=B5=D1=82=D0=BE=D0=B4=D1=8B-=D0=B3=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D1=80=D0=B0=D1=82=D0=BE=D1=80=D1=8B=20=D1=81=D0=BE?= =?UTF-8?q?=D1=80=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=BE=D0=BA=20=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D0=BF=D0=B8=D1=81=D0=B0=D0=BD=D1=8B=20=D1=81=20?= =?UTF-8?q?=D1=83=D1=87=D1=91=D1=82=D0=BE=D0=BC=20=D1=81=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D0=B0=D0=B2=D0=BD=D1=8B=D1=85=20=D0=BA=D0=BB=D1=8E=D1=87=D0=B5?= =?UTF-8?q?=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Table/Columns/date.tsx | 28 ++++-- src/components/Table/Columns/index.ts | 23 +++-- src/components/Table/Columns/numeric.tsx | 73 +++++++++------ src/components/Table/Columns/plan_fact.tsx | 36 +++----- src/components/Table/Columns/select.tsx | 19 ++-- src/components/Table/Columns/tag.tsx | 6 +- src/components/Table/Columns/text.tsx | 19 +++- src/components/Table/Columns/time.tsx | 27 ++++-- src/components/Table/Columns/timezone.tsx | 16 ++-- src/components/Table/EditableCell.tsx | 88 +++++++++++-------- src/components/Table/Table.tsx | 57 ++++++++++-- src/components/Table/TableSettingsChanger.tsx | 12 +-- src/components/Table/index.tsx | 1 - src/components/Table/sorters.ts | 42 --------- .../Well/WellOperations/WellDrillParams.jsx | 73 +-------------- 15 files changed, 251 insertions(+), 269 deletions(-) delete mode 100755 src/components/Table/sorters.ts diff --git a/src/components/Table/Columns/date.tsx b/src/components/Table/Columns/date.tsx index d4790e6..a401a04 100755 --- a/src/components/Table/Columns/date.tsx +++ b/src/components/Table/Columns/date.tsx @@ -1,26 +1,36 @@ -import { ReactNode } from 'react' +import { Key, ReactNode } from 'react' -import { formatDate } from '@utils' - -import makeColumn, { columnPropsOther } from '.' -import { DatePickerWrapper, makeDateSorter } from '..' +import { makeColumn, ColumnProps, SorterMethod } from '.' +import { DatePickerWrapper, getObjectByDeepKey } from '..' import { DatePickerWrapperProps } from '../DatePickerWrapper' +import { formatDate, isRawDate } from '@utils' -export const makeDateColumn = ( +export const makeDateSorter = (key: Key): SorterMethod => (a, b) => { + const vA = a ? getObjectByDeepKey(key, a) : null + const vB = b ? getObjectByDeepKey(key, b) : null + + if (!isRawDate(vA) || !isRawDate(vB)) return 0 + if (!isRawDate(vA)) return 1 + if (!isRawDate(vB)) return -1 + + return (new Date(vA)).getTime() - (new Date(vB)).getTime() +} + +export const makeDateColumn = ( title: ReactNode, key: string, utc?: boolean, format?: string, - other?: columnPropsOther, + other?: ColumnProps, pickerOther?: DatePickerWrapperProps, -) => makeColumn(title, key, { +) => makeColumn(title, key, { ...other, render: (date) => (
{formatDate(date, utc, format) ?? '-'}
), - sorter: makeDateSorter(key), + sorter: makeDateSorter(key), input: , }) diff --git a/src/components/Table/Columns/index.ts b/src/components/Table/Columns/index.ts index b8cb6ef..778bffd 100755 --- a/src/components/Table/Columns/index.ts +++ b/src/components/Table/Columns/index.ts @@ -1,6 +1,10 @@ -import { ReactNode } from 'react' +import { Key, ReactNode } from 'react' import { Rule } from 'antd/lib/form' -import { ColumnProps } from 'antd/lib/table' +import { ColumnType } from 'antd/lib/table' +import { RenderedCell } from 'rc-table/lib/interface' + +import { DataSet } from '../Table' +import { OmitExtends } from '@utils/types' export * from './date' export * from './time' @@ -12,10 +16,13 @@ export * from './text' export * from './timezone' export type DataType = Record -export type RenderMethod = (value: T, dataset?: DataType, index?: number) => ReactNode -export type SorterMethod = (a?: DataType | null, b?: DataType | null) => number +export type RenderMethod> = (value: T | undefined, dataset: DT, index: number) => ReactNode | RenderedCell | undefined +export type SorterMethod | null | undefined> = (a: DT, b: DT) => number +export type FilterMethod> = (value: string | number | T | undefined, record: DT) => boolean -export type columnPropsOther = ColumnProps> & { +export type FilterGenerator> = (key: Key) => FilterMethod + +export type ColumnProps = OmitExtends<{ // редактируемая колонка editable?: boolean // react компонента редактора @@ -29,10 +36,12 @@ export type columnPropsOther = ColumnProps> & { // дефолтное значение при добавлении новой строки initialValue?: string | number + onFilter?: FilterMethod + sorter?: SorterMethod render?: RenderMethod -} +}, ColumnType>> -export const makeColumn = (title: ReactNode, key: string, other?: columnPropsOther) => ({ +export const makeColumn = (title: ReactNode, key: Key, other?: ColumnProps) => ({ title: title, key: key, dataIndex: key, diff --git a/src/components/Table/Columns/numeric.tsx b/src/components/Table/Columns/numeric.tsx index ad8fdee..36f89b2 100755 --- a/src/components/Table/Columns/numeric.tsx +++ b/src/components/Table/Columns/numeric.tsx @@ -1,20 +1,26 @@ +import { ColumnFilterItem } from 'antd/lib/table/interface' import { InputNumber } from 'antd' -import { ReactNode } from 'react' +import { Key, ReactNode } from 'react' -import { makeNumericSorter } from '../sorters' -import makeColumn, { columnPropsOther, DataType, makeGroupColumn, RenderMethod } from '.' -import { ColumnFilterItem, CompareFn } from 'antd/lib/table/interface' +import makeColumn, { ColumnProps, FilterGenerator, makeGroupColumn, RenderMethod, SorterMethod } from '.' +import { getObjectByDeepKey } from '../Table' export const RegExpIsFloat = /^[-+]?\d+\.?\d*$/ -type FilterMethod = (value: string | number | boolean, record: DataType) => boolean +export const makeNumericSorter = (key: Key): SorterMethod => (a, b) => { + if (!a && !b) return 0 + if (!a) return 1 + if (!b) return -1 -export const makeNumericRender = (fixed?: number): RenderMethod => (value: T) => { - let val = '-' - if ((value ?? null) !== null && Number.isFinite(+value)) { + return Number(getObjectByDeepKey(key, a)) - Number(getObjectByDeepKey(key, b)) +} + +export const makeNumericRender = (fixed?: number, defaultValue: string = '-', precision: number = 5): RenderMethod => (value) => { + let val = defaultValue + if (value !== undefined && value !== null && Number.isFinite(+value)) { val = (fixed ?? null) !== null ? (+value).toFixed(fixed) - : (+value).toPrecision(5) + : (+value).toPrecision(precision) } return ( @@ -24,7 +30,7 @@ export const makeNumericRender = (fixed?: number): RenderMeth ) } -export const makeNumericColumnOptions = (fixed?: number, sorterKey?: string): columnPropsOther => ({ +export const makeNumericColumnOptions = (fixed?: number, sorterKey?: string): ColumnProps => ({ editable: true, initialValue: 0, width: 100, @@ -37,14 +43,14 @@ export const makeNumericColumnOptions = (fixed?: number render: makeNumericRender(fixed), }) -export const makeNumericColumn = ( +export const makeNumericColumn = ( title: ReactNode, - key: string, + key: Key, filters?: ColumnFilterItem[], - filterDelegate?: (key: string | number) => FilterMethod, + filterDelegate?: FilterGenerator, renderDelegate?: RenderMethod, width?: string | number, - other?: columnPropsOther, + other?: ColumnProps, ) => makeColumn(title, key, { filters, onFilter: filterDelegate ? filterDelegate(key) : undefined, @@ -56,24 +62,25 @@ export const makeNumericColumn = ( ...other }) -export const makeNumericColumnPlanFact = ( +export const makeNumericColumnPlanFact = ( title: ReactNode, - key: string, + key: Key, filters?: ColumnFilterItem[], - filterDelegate?: (key: string | number) => FilterMethod, + filterDelegate?: FilterGenerator, renderDelegate?: RenderMethod, - width?: string | number + width?: string | number, + other?: ColumnProps, ) => makeGroupColumn(title, [ - makeNumericColumn('п', key + 'Plan', filters, filterDelegate, renderDelegate, width), - makeNumericColumn('ф', key + 'Fact', filters, filterDelegate, renderDelegate, width), + makeNumericColumn('п', key + 'Plan', filters, filterDelegate, renderDelegate, width, other), + makeNumericColumn('ф', key + 'Fact', filters, filterDelegate, renderDelegate, width, other), ]) -export const makeNumericStartEnd = ( +export const makeNumericStartEnd = ( title: ReactNode, - key: string, + key: Key, fixed: number, filters?: ColumnFilterItem[], - filterDelegate?: (key: string | number) => FilterMethod, + filterDelegate?: FilterGenerator, renderDelegate?: RenderMethod, width?: string | number, ) => makeGroupColumn(title, [ @@ -81,12 +88,12 @@ export const makeNumericStartEnd = ( makeNumericColumn('конец', key + 'End', filters, filterDelegate, renderDelegate, width, makeNumericColumnOptions(fixed, key + 'End')) ]) -export const makeNumericMinMax = ( +export const makeNumericMinMax = ( title: ReactNode, - key: string, + key: Key, fixed: number, filters?: ColumnFilterItem[], - filterDelegate?: (key: string | number) => FilterMethod, + filterDelegate?: FilterGenerator, renderDelegate?: RenderMethod, width?: string | number, ) => makeGroupColumn(title, [ @@ -94,4 +101,18 @@ export const makeNumericMinMax = ( makeNumericColumn('макс', key + 'Max', filters, filterDelegate, renderDelegate, width, makeNumericColumnOptions(fixed, key + 'Max')), ]) +export const makeNumericAvgRange = ( + title: ReactNode, + key: Key, + fixed: number, + filters?: ColumnFilterItem[], + filterDelegate?: FilterGenerator, + renderDelegate?: RenderMethod, + width?: string | number, +) => makeGroupColumn(title, [ + makeNumericColumn('мин', `${key}.min`, filters, filterDelegate, renderDelegate, width, makeNumericColumnOptions(fixed, `${key}.min`)), + makeNumericColumn('сред', `${key}.avg`, filters, filterDelegate, renderDelegate, width, makeNumericColumnOptions(fixed, `${key}.avg`)), + makeNumericColumn('макс', `${key}.max`, filters, filterDelegate, renderDelegate, width, makeNumericColumnOptions(fixed, `${key}.max`)), +]) + export default makeNumericColumn diff --git a/src/components/Table/Columns/plan_fact.tsx b/src/components/Table/Columns/plan_fact.tsx index e890eec..852b9e4 100755 --- a/src/components/Table/Columns/plan_fact.tsx +++ b/src/components/Table/Columns/plan_fact.tsx @@ -1,36 +1,20 @@ -import { ReactNode } from 'react' +import { Key, ReactNode } from 'react' -import { columnPropsOther, makeColumn } from '.' +import { ColumnProps, makeColumn } from '.' -export const makeColumnsPlanFact = ( +export const makeColumnsPlanFact = ( title: string | ReactNode, - key: string | string[], - columsOther?: columnPropsOther | [columnPropsOther, columnPropsOther], - gruopOther?: any + key: Key | [Key, Key], + columsOther?: ColumnProps | [ColumnProps, ColumnProps], ) => { - let keyPlanLocal: string - let keyFactLocal: string - - if (key instanceof Array) { - keyPlanLocal = key[0] - keyFactLocal = key[1] - } else { - keyPlanLocal = key + 'Plan' - keyFactLocal = key + 'Fact' - } - - let columsOtherLocal : any[2] - if (columsOther instanceof Array) - columsOtherLocal = [columsOther[0], columsOther[1]] - else - columsOtherLocal = [columsOther, columsOther] + const keys = Array.isArray(key) ? key : [`${key}Plan`, `${key}Fact`] + const others = Array.isArray(columsOther) ? columsOther : [columsOther, columsOther] return { - title: title, - ...gruopOther, + title, children: [ - makeColumn('план', keyPlanLocal, columsOtherLocal[0]), - makeColumn('факт', keyFactLocal, columsOtherLocal[1]), + makeColumn('план', keys[0], others[0]), + makeColumn('факт', keys[1], others[1]), ] } } diff --git a/src/components/Table/Columns/select.tsx b/src/components/Table/Columns/select.tsx index fefc00f..098d983 100755 --- a/src/components/Table/Columns/select.tsx +++ b/src/components/Table/Columns/select.tsx @@ -1,21 +1,22 @@ import { Select, SelectProps } from 'antd' import { DefaultOptionType, SelectValue } from 'antd/lib/select' +import { Key, ReactNode } from 'react' -import { columnPropsOther, makeColumn } from '.' +import { ColumnProps, makeColumn } from '.' -export const makeSelectColumn = ( - title: string, - dataIndex: string, - options: DefaultOptionType[], +export const makeSelectColumn = ( + title: ReactNode, + key: Key, + options: T[], defaultValue?: T, - other?: columnPropsOther, + other?: ColumnProps, selectOther?: SelectProps -) => makeColumn(title, dataIndex, { +) => makeColumn(title, key, { ...other, input: ) }) -export const makeTimezoneColumn = ( +export const makeTimezoneColumn = ( title: ReactNode = 'Зона', - key: string = 'timezone', - defaultValue?: SimpleTimezoneDto, + key: Key = 'timezone', + defaultValue?: T, allowClear: boolean = true, - other?: columnPropsOther, + other?: ColumnProps, selectOther?: TimezoneSelectProps ) => makeColumn(title, key, { width: 100, editable: true, - render: makeTimezoneRenderer(), + render: makeTimezoneRender(), input: ( , HTMLTableDataCellElement> & { - editing?: boolean - dataIndex?: NamePath - input?: ReactNode - isRequired?: boolean - title: string - formItemClass?: string - formItemRules?: Rule[] - children: ReactNode - initialValue: any +export type EditableCellProps = React.DetailedHTMLProps, HTMLTableDataCellElement> & { + editing?: boolean + dataIndex?: Key + input?: ReactNode + isRequired?: boolean + formItemClass?: string + formItemRules?: Rule[] + children: ReactNode + initialValue: any } +const itemStyle = { margin: 0 } + export const EditableCell = memo(({ - editing, - dataIndex, - input, - isRequired, - formItemClass, - formItemRules, - children, - initialValue, - ...other -}) => ( - - {!editing ? children : ( - - {input ?? } - - )} - -)) + editing, + dataIndex, + input, + isRequired, + formItemClass, + formItemRules, + children, + initialValue, + ...other +}) => { + const rules = useMemo(() => formItemRules || [{ + required: isRequired, + message: `Это обязательное поле!`, + }], [formItemRules, isRequired]) + + const name = useMemo(() => dataIndex ? String(dataIndex).split('.') : undefined, [dataIndex]) + const tdStyle = useMemo(() => editing ? { padding: 0 } : undefined, [editing]) + + const edititngItem = useMemo(() => ( + + {input ?? } + + ), [name, rules, formItemClass, initialValue, input]) + + return ( + + {editing ? edititngItem : children} + + ) +}) diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx index 3b25a0d..c9ecbbe 100755 --- a/src/components/Table/Table.tsx +++ b/src/components/Table/Table.tsx @@ -1,26 +1,65 @@ -import { memo, useCallback, useEffect, useState } from 'react' +import { Key, memo, useCallback, useEffect, useState } from 'react' import { ColumnGroupType, ColumnType } from 'antd/lib/table' import { Table as RawTable, TableProps } from 'antd' +import { RenderMethod } from './Columns' +import { tryAddKeys } from './EditableTable' +import TableSettingsChanger from './TableSettingsChanger' import type { OmitExtends } from '@utils/types' import { applyTableSettings, getTableSettings, setTableSettings, TableColumnSettings, TableSettings } from '@utils' -import TableSettingsChanger from './TableSettingsChanger' -import { tryAddKeys } from './EditableTable' - import '@styles/index.css' export type BaseTableColumn = ColumnGroupType | ColumnType -export type TableColumns = OmitExtends, TableColumnSettings>[] +export type TableColumn = OmitExtends, TableColumnSettings> +export type TableColumns = TableColumn[] export type TableContainer = TableProps & { - columns: TableColumns + columns: TableColumn[] tableName?: string showSettingsChanger?: boolean } -const _Table = ({ columns, dataSource, tableName, showSettingsChanger, ...other }: TableContainer) => { - const [newColumns, setNewColumns] = useState>([]) +export interface DataSet { + [k: Key]: DataSet | T | D +} + +export const getObjectByDeepKey = (key: Key | undefined, data: DataSet): T | undefined => { + if (!key) return undefined + const parts = String(key).split('.') + let out = data + for (let i = 0; i < parts.length && out; i++) { + const key = parts[i] + if (!(key in out)) return undefined // Если ключ не найдем, считаем значение null + out = out[key] as DataSet // Углубляемся внутрь объекта + } + return out as T +} + +export const makeColumnRenderWrapper = >(key: Key | undefined, render: RenderMethod | undefined): RenderMethod => + (_: any, dataset: T, index: number) => { + const renderFunc: RenderMethod = typeof render === 'function' ? render : (record) => String(record) + return renderFunc(getObjectByDeepKey(key, dataset), dataset, index) + } + + +const applyColumnWrappers = >(columns: BaseTableColumn[]): BaseTableColumn[] => { + return columns.map((column) => { + if ('children' in column) { + return { + ...column, + children: applyColumnWrappers(column.children), + } + } + return { + ...column, + render: makeColumnRenderWrapper(column.key, column.render), + } + }) +} + +function _Table>({ columns, dataSource, tableName, showSettingsChanger, ...other }: TableContainer) { + const [newColumns, setNewColumns] = useState[]>([]) const [settings, setSettings] = useState({}) const onSettingsChanged = useCallback((settings?: TableSettings | null) => { @@ -31,7 +70,7 @@ const _Table = ({ columns, dataSource, tableName, showSettings useEffect(() => setSettings(tableName ? getTableSettings(tableName) : {}), [tableName]) useEffect(() => setNewColumns(() => { - const newColumns = applyTableSettings(columns, settings) + const newColumns = applyTableSettings(applyColumnWrappers(columns), settings) if (tableName && showSettingsChanger) { const oldTitle = newColumns[0].title newColumns[0].title = (props) => ( diff --git a/src/components/Table/TableSettingsChanger.tsx b/src/components/Table/TableSettingsChanger.tsx index 4ca622f..2bbb805 100755 --- a/src/components/Table/TableSettingsChanger.tsx +++ b/src/components/Table/TableSettingsChanger.tsx @@ -1,11 +1,11 @@ import { memo, useCallback, useEffect, useState } from 'react' import { ColumnsType } from 'antd/lib/table' -import { Button, Modal, Switch, Table } from 'antd' +import { Button, Modal, Switch } from 'antd' import { SettingOutlined } from '@ant-design/icons' import { TableColumnSettings, makeTableSettings, mergeTableSettings, TableSettings } from '@utils' -import { TableColumns } from './Table' -import { makeColumn } from '.' +import { Table, TableColumns } from './Table' +import { makeColumn, makeTextColumn } from '.' const parseSettings = (columns?: TableColumns, settings?: TableSettings | null): TableColumnSettings[] => { const newSettings = mergeTableSettings(makeTableSettings(columns ?? []), settings ?? {}) @@ -46,8 +46,8 @@ const _TableSettingsChanger = ({ title, columns, settings, onC useEffect(() => { setTableColumns([ - makeColumn('Название', 'title'), - makeColumn(null, 'visible', { + makeTextColumn('Название', 'title'), + makeColumn(null, 'visible', { title: () => ( <> Показать @@ -56,7 +56,7 @@ const _TableSettingsChanger = ({ title, columns, settings, onC ), - render: (visible: boolean, _?: TableColumnSettings, index: number = NaN) => ( + render: (visible, _, index = NaN) => ( (key: keyof DataType): CompareFn> => - (a: DataType, b: DataType) => Number(a[key]) - Number(b[key]) - -export const makeNumericObjSorter = (key: [string, string]) => - (a: DataType, b: DataType) => Number(a[key[0]][key[1]]) - Number(b[key[0]][key[1]]) - -export const makeStringSorter = (key: keyof DataType) => (a?: DataType | null, b?: DataType | null) => { - if (!a && !b) return 0 - if (!a) return 1 - if (!b) return -1 - - return String(a[key]).localeCompare(String(b[key])) -} - -export const makeDateSorter = (key: keyof DataType) => (a: DataType, b: DataType) => { - const adate = a[key] - const bdate = b[key] - if (!isRawDate(adate) || !isRawDate(bdate)) - throw new Error('Date column contains not date formatted string(s)') - - const date = new Date(adate) - - return date.getTime() - new Date(bdate).getTime() -} - -export const makeTimeSorter = (key: keyof DataType) => (a: DataType, b: DataType) => { - const elma = a[key] - const elmb = b[key] - - if (!elma && !elmb) return 0 - if (!elma) return 1 - if (!elmb) return -1 - - return timeToMoment(elma).diff(timeToMoment(elmb)) -} diff --git a/src/pages/Well/WellOperations/WellDrillParams.jsx b/src/pages/Well/WellOperations/WellDrillParams.jsx index 486b422..0ae6097 100644 --- a/src/pages/Well/WellOperations/WellDrillParams.jsx +++ b/src/pages/Well/WellOperations/WellDrillParams.jsx @@ -1,88 +1,17 @@ import { useState, useEffect, useCallback, memo, useMemo } from 'react' -import { InputNumber } from 'antd' import { useWell } from '@asb/context' import { EditableTable, makeSelectColumn, - makeGroupColumn, - makeNumericRender, makeNumericSorter, - RegExpIsFloat, + makeNumericAvgRange, } from '@components/Table' import LoaderPortal from '@components/LoaderPortal' import { invokeWebApiWrapperAsync } from '@components/factory' import { DrillParamsService, WellOperationService } from '@api' import { arrayOrDefault } from '@utils' -import { makeNumericObjSorter } from '@components/Table/sorters' - -const makeNumericObjRender = (fixed, columnKey) => (value, obj) => { - let val = '-' - const isSelected = obj && columnKey && obj[columnKey[0]] ? obj[columnKey[0]][columnKey[1]] : false - - if ((value ?? null) !== null && Number.isFinite(+value)) { - val = (fixed ?? null) !== null - ? (+value).toFixed(fixed) - : (+value).toPrecision(5) - } - - return ( -
- {val} -
- ) -} - -const makeNumericColumnOptionsWithColor = (fixed, sorterKey, columnKey) => ({ - editable: true, - initialValue: 0, - width: 100, - sorter: sorterKey ? makeNumericObjSorter(sorterKey) : undefined, - formItemRules: [{ - required: true, - message: 'Введите число', - pattern: RegExpIsFloat, - }], - render: makeNumericObjRender(fixed, columnKey), -}) - -const makeNumericObjColumn = ( - title, - dataIndex, - filters, - filterDelegate, - renderDelegate, - width, - other -) => ({ - title: title, - dataIndex: dataIndex, - key: dataIndex, - filters: filters, - onFilter: filterDelegate ? filterDelegate(dataIndex) : null, - sorter: makeNumericObjSorter(dataIndex), - width: width, - input: , - render: renderDelegate ?? makeNumericRender(), - align: 'right', - ...other -}) - -const makeNumericAvgRange = ( - title, - dataIndex, - fixed, - filters, - filterDelegate, - renderDelegate, - width -) => makeGroupColumn(title, [ - makeNumericObjColumn('мин', [dataIndex, 'min'], filters, filterDelegate, renderDelegate, width, makeNumericColumnOptionsWithColor(fixed, [dataIndex, 'min'], [dataIndex, 'isMin'])), - makeNumericObjColumn('сред', [dataIndex, 'avg'], filters, filterDelegate, renderDelegate, width, makeNumericColumnOptionsWithColor(fixed, [dataIndex, 'avg'])), - makeNumericObjColumn('макс', [dataIndex, 'max'], filters, filterDelegate, renderDelegate, width, makeNumericColumnOptionsWithColor(fixed, [dataIndex, 'max'], [dataIndex, 'isMax'])) -]) - export const getColumns = async (idWell) => { let sectionTypes = await WellOperationService.getSectionTypes(idWell) sectionTypes = Object.entries(sectionTypes).map(([id, value]) => ({