diff --git a/src/components/Layout/LayoutPortal.tsx b/src/components/Layout/LayoutPortal.tsx index e8396aa..ff915b0 100755 --- a/src/components/Layout/LayoutPortal.tsx +++ b/src/components/Layout/LayoutPortal.tsx @@ -8,12 +8,13 @@ import { wrapPrivateComponent } from '@utils' export type LayoutPortalProps = LayoutProps & { title?: ReactNode noSheet?: boolean + showSelector?: boolean } -const _LayoutPortal = memo(({ title, noSheet, ...props }) => ( +const _LayoutPortal = memo(({ title, noSheet, showSelector, ...props }) => ( - + {noSheet ? props.children : ( diff --git a/src/components/PageHeader.tsx b/src/components/PageHeader.tsx index 8a2b5d5..1db85e2 100755 --- a/src/components/PageHeader.tsx +++ b/src/components/PageHeader.tsx @@ -1,6 +1,6 @@ import { memo } from 'react' -import { Link, useLocation } from 'react-router-dom' import { Layout } from 'antd' +import { Link, useLocation } from 'react-router-dom' import { BasicProps } from 'antd/lib/layout/layout' import { headerHeight } from '@utils' @@ -23,8 +23,8 @@ export const PageHeader: React.FC = memo(({ title = 'Монит - {children}

{title}

+ {children}
diff --git a/src/components/selectors/WellTreeSelector.tsx b/src/components/selectors/WellTreeSelector.tsx index 90e7bdc..1cb8add 100755 --- a/src/components/selectors/WellTreeSelector.tsx +++ b/src/components/selectors/WellTreeSelector.tsx @@ -1,15 +1,12 @@ -import { TreeSelect } from 'antd' -import { LabelInValueType } from 'rc-select/lib/Select' -import { RawValueType } from 'rc-tree-select/lib/TreeSelect' +import { Button, Drawer, Tree, TreeProps, Typography } from 'antd' import { DefaultValueType } from 'rc-tree-select/lib/interface' -import { useState, useEffect, ReactNode, useCallback, memo } from 'react' +import { useState, useEffect, ReactNode, useCallback, memo, Key } from 'react' import { useNavigate, useLocation } from 'react-router-dom' -import { isRawDate } from '@utils' -import LoaderPortal from '@components/LoaderPortal' import { WellIcon, WellIconState } from '@components/icons' import { invokeWebApiWrapperAsync } from '@components/factory' -import { DepositService, DepositDto } from '@api' +import { DepositService, DepositDto, WellDto } from '@api' +import { isRawDate } from '@utils' import { ReactComponent as DepositIcon } from '@images/DepositIcon.svg' import { ReactComponent as ClusterIcon } from '@images/ClusterIcon.svg' @@ -28,10 +25,15 @@ export type TreeNodeData = { children?: TreeNodeData[] } +const getKeyByUrl = (url?: string): [Key | null, string | null] => { + const result = url?.match(/^\/([^\/]+)\/([^\/?]+)/) // pattern "/:type/:id" + if (!result) return [null, null] + return [result[0], result[1]] +} + const getLabel = (wellsTree: TreeNodeData[], value?: string): string | undefined => { - const result = value?.match(/^\/([^\/]+)\/([^\/?]+)/) // pattern "/:type/:id" - if (wellsTree.length <= 0 || !result) return - const [url, type] = result + const [url, type] = getKeyByUrl(value) + if (!url) return let deposit: TreeNodeData | undefined let cluster: TreeNodeData | undefined let well: TreeNodeData | undefined @@ -64,13 +66,47 @@ const getLabel = (wellsTree: TreeNodeData[], value?: string): string | undefined } } -export const WellTreeSelector = memo(({ ...other }) => { +const getWellSortScore = (well: WellDto) => { + let out = [1, 2, 0][well.idState ?? 2] + const timeout = Date.now() - +new Date(well.lastTelemetryDate || 0) + if (timeout < 600_000) out += 600_000 - timeout + console.log(well, out) + return out +} + +const sortWellsByActive = (a: WellDto, b: WellDto): number => { + const score = getWellSortScore(b) - getWellSortScore(a) + if (score !== 0) return score + return (a.caption || '')?.localeCompare(b.caption || '') +} + +export const WellTreeSelector = memo(({ show, ...other }: TreeProps & { show?: boolean }) => { const [wellsTree, setWellsTree] = useState([]) const [showLoader, setShowLoader] = useState(false) + const [visible, setVisible] = useState(false) + const [expanded, setExpanded] = useState([]) + const [selected, setSelected] = useState([]) const [value, setValue] = useState() + const navigate = useNavigate() const location = useLocation() + useEffect(() => { + setVisible((prev) => show ?? prev) + setExpanded((prev) => { + if (typeof show === 'undefined') return prev + if (!show) return [] + const out: Key[] = [] + wellsTree.forEach((deposit) => { + if (deposit.key) out.push(deposit.key) + deposit.children?.forEach((cluster) => { + if (cluster.key) out.push(cluster.key) + }) + }) + return out + }) + }, [wellsTree, show]) + useEffect(() => { invokeWebApiWrapperAsync( async () => { @@ -80,23 +116,28 @@ export const WellTreeSelector = memo(({ ...other }) => { key: `/deposit/${deposit.id}`, value: `/deposit/${deposit.id}`, icon: , - children: deposit.clusters?.map(cluster => ({ - title: cluster.caption, - key: `/cluster/${cluster.id}`, - value: `/cluster/${cluster.id}`, - icon: , - children: cluster.wells?.map(well => ({ - title: well.caption, - key: `/well/${well.id}`, - value: `/well/${well.id}`, - icon: - })), - })), + children: deposit.clusters?.map(cluster => { + const wells = cluster.wells ? cluster.wells.slice() : [] + wells.sort(sortWellsByActive) + + return { + title: cluster.caption, + key: `/cluster/${cluster.id}`, + value: `/cluster/${cluster.id}`, + icon: , + children: wells.map(well => ({ + title: well.caption, + key: `/well/${well.id}`, + value: `/well/${well.id}`, + icon: + })), + } + }), })) setWellsTree(wellsTree) }, @@ -106,32 +147,34 @@ export const WellTreeSelector = memo(({ ...other }) => { ) }, []) - useEffect(() => setValue(getLabel(wellsTree, location.pathname)), [wellsTree, location]) + const onChange = useCallback((value?: string): void => { + const key = getKeyByUrl(value)[0] + setSelected(key ? [key] : []) + setValue(getLabel(wellsTree, value)) + }, [wellsTree]) - const onChange = useCallback((value?: string): void => setValue(getLabel(wellsTree, value)), [wellsTree]) - - const onSelect = useCallback((value: RawValueType | LabelInValueType): void => { - if (['number', 'string'].includes(typeof value)) - navigate(String(value), { state: { from: location.pathname }}) + const onSelect = useCallback((value: Key[]): void => { + navigate(String(value), { state: { from: location.pathname }}) }, [navigate, location]) + useEffect(() => onChange(location.pathname), [onChange, location]) + return ( - - - + <> + + setVisible(false)}> + Список скважин + + + ) }) diff --git a/src/pages/Deposit.jsx b/src/pages/Deposit.jsx index 72e5dff..506c68f 100755 --- a/src/pages/Deposit.jsx +++ b/src/pages/Deposit.jsx @@ -62,7 +62,7 @@ const Deposit = memo(() => { }, []) return ( - +
diff --git a/src/pages/Telemetry/Operations/OperationsChart.jsx b/src/pages/Telemetry/Operations/OperationsChart.jsx index 2726654..a0e7e82 100644 --- a/src/pages/Telemetry/Operations/OperationsChart.jsx +++ b/src/pages/Telemetry/Operations/OperationsChart.jsx @@ -94,7 +94,7 @@ export const OperationsChart = memo(({ data, yDomain, height, category, onDomain tooltip: { enabled: true, type: 'nearest', - height: 200, + height: 225, limit: 4, render: makeTooltipRender(category), }, diff --git a/src/styles/App.less b/src/styles/App.less index 600ca7a..cc55b30 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: 100px; + padding-left: 450px; } .header button{