forked from ddrilling/asb_cloud_front
199 lines
7.8 KiB
TypeScript
Executable File
199 lines
7.8 KiB
TypeScript
Executable File
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
|