asb_cloud_front/src/components/selectors/WellTreeSelector.tsx

199 lines
7.8 KiB
TypeScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Button, Drawer, Skeleton, Tree, TreeDataNode, TreeProps, Typography } from 'antd'
import { useState, useEffect, useCallback, memo, Key } from 'react'
import { useNavigate, useLocation } from 'react-router-dom'
import { WellIcon, WellIconState } from '@components/icons'
import { invokeWebApiWrapperAsync } from '@components/factory'
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'
import '@styles/wellTreeSelect.css'
export const getWellState = (idState?: number): WellIconState => idState === 1 ? 'active' : 'unknown'
export const checkIsWellOnline = (lastTelemetryDate: unknown): boolean =>
isRawDate(lastTelemetryDate) && (Date.now() - +new Date(lastTelemetryDate) < 600_000)
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: TreeDataNode[], value?: string): string | undefined => {
const [url, type] = getKeyByUrl(value)
if (!url) return
let deposit: TreeDataNode | undefined
let cluster: TreeDataNode | undefined
let well: TreeDataNode | undefined
switch (type) {
case 'deposit':
deposit = wellsTree.find((deposit) => deposit.key === url)
if (deposit)
return `${deposit.title}`
return 'Ошибка! Месторождение не найдено!'
case 'cluster':
deposit = wellsTree.find((deposit) => (
cluster = deposit.children?.find((cluster: TreeDataNode) => cluster.key === url)
))
if (deposit && cluster)
return `${deposit.title} / ${cluster.title}`
return 'Ошибка! Куст не найден!'
case 'well':
deposit = wellsTree.find((deposit) => (
cluster = deposit.children?.find((cluster: TreeDataNode) => (
well = cluster.children?.find((well: TreeDataNode) => well.key === url)
))
))
if (deposit && cluster && well)
return `${deposit.title} / ${cluster.title} / ${well.title}`
return 'Ошибка! Скважина не найдена!'
default: break
}
}
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
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 type WellTreeSelectorProps = TreeProps<TreeDataNode> & {
show?: boolean
expand?: boolean | Key[]
current?: Key
}
const getExpandKeys = (treeData: TreeDataNode[], depositKeys?: Key[] | boolean): Key[] => {
const out: Key[] = []
treeData.forEach((deposit) => {
if (Array.isArray(depositKeys) && !depositKeys.includes(deposit.key)) return
if (deposit.key) out.push(deposit.key)
deposit.children?.forEach((cluster) => {
if (cluster.key) out.push(cluster.key)
})
})
return out
}
export const WellTreeSelector = memo<WellTreeSelectorProps>(({ show, expand, current, ...other }) => {
const [wellsTree, setWellsTree] = useState<TreeDataNode[]>([])
const [showLoader, setShowLoader] = useState<boolean>(false)
const [visible, setVisible] = useState<boolean>(false)
const [expanded, setExpanded] = useState<Key[]>([])
const [selected, setSelected] = useState<Key[]>([])
const [value, setValue] = useState<string>()
const navigate = useNavigate()
const location = useLocation()
console.log(location.pathname)
useEffect(() => {
if (current) setSelected([current])
}, [current])
useEffect(() => setVisible((prev) => show ?? prev), [show])
useEffect(() => {
setExpanded((prev) => expand ? getExpandKeys(wellsTree, expand) : prev)
}, [wellsTree, expand])
useEffect(() => {
invokeWebApiWrapperAsync(
async () => {
const deposits: Array<DepositDto> = await DepositService.getDeposits()
const wellsTree: TreeDataNode[] = deposits.map(deposit =>({
title: deposit.caption,
key: `/deposit/${deposit.id}`,
value: `/deposit/${deposit.id}`,
icon: <DepositIcon width={24} height={24}/>,
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: <ClusterIcon width={24} height={24}/>,
children: wells.map(well => ({
title: well.caption,
key: `/well/${well.id}`,
value: `/well/${well.id}`,
icon: <WellIcon
width={24}
height={24}
state={getWellState(well.idState)}
online={checkIsWellOnline(well.lastTelemetryDate)}
/>
})),
}
}),
}))
setWellsTree(wellsTree)
},
setShowLoader,
`Не удалось загрузить список скважин`,
{ actionName: 'Получить список скважин' }
)
}, [])
const onChange = useCallback((value?: string): void => {
const key = getKeyByUrl(value)[0]
setSelected(key ? [key] : [])
setValue(getLabel(wellsTree, value))
}, [wellsTree])
const onSelect = useCallback((value: Key[]): void => {
const newRoot = /\/(\w+)\/\d+/.exec(String(value))
const oldRoot = /\/(\w+)(?:\/\d+)?/.exec(location.pathname)
if (!newRoot || !oldRoot) return
let newPath = newRoot[0]
if (oldRoot[1] === newRoot[1]) {
/// Если типы страницы одинаковые (deposit, cluster, well), добавляем остаток старого пути
const url = location.pathname.substring(oldRoot[0].length)
newPath = newPath + url
}
navigate(newPath, { state: { from: location.pathname }})
}, [navigate, location])
useEffect(() => onChange(location.pathname), [onChange, location])
return (
<>
<Button loading={showLoader} onClick={() => setVisible(true)}>{value ?? 'Выберите месторождение'}</Button>
<Drawer visible={visible} mask={false} onClose={() => setVisible(false)}>
<Typography.Title level={3}>Список скважин</Typography.Title>
<Skeleton active loading={showLoader}>
<Tree
{...other}
showIcon
selectedKeys={selected}
treeData={wellsTree}
onSelect={onSelect}
onExpand={setExpanded}
expandedKeys={expanded}
/>
</Skeleton>
</Drawer>
</>
)
})
export default WellTreeSelector