В телеметрию админ-панели добавлена страница объединения, добавлены кнопки на странице просмотра для перехода к объединению

This commit is contained in:
Александр Сироткин 2022-03-23 14:30:48 +05:00
parent c2eac25470
commit befac57c30
6 changed files with 247 additions and 35 deletions

View File

@ -4,7 +4,7 @@ import { Tooltip } from 'antd'
import { TelemetryDto, TelemetryInfoDto } from '@api'
import { Grid, GridItem } from '@components/Grid'
const lables: Record<string, string> = {
export const lables: Record<string, string> = {
timeZoneId: 'Временная зона',
timeZoneOffsetTotalHours: 'Сдвиг временной зоны',
drillingStartDate: 'Начало бурения',

View File

@ -0,0 +1,136 @@
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
import { useLocation } from 'react-router-dom'
import { PullRequestOutlined } from '@ant-design/icons'
import { Button, Descriptions, Popconfirm } from 'antd'
import { Grid, GridItem } from '@components/Grid'
import LoaderPortal from '@components/LoaderPortal'
import { lables } from '@components/views/TelemetryView'
import { invokeWebApiWrapperAsync } from '@components/factory'
import TelemetrySelect from '@components/selectors/TelemetrySelect'
import { AdminTelemetryService } from '@api'
import { arrayOrDefault } from '@utils'
const { Item } = Descriptions
export const TelemetryInfo = memo(({ info, danger, ...other }) => (
<Descriptions
bordered
column={1}
size={'small'}
style={{ background: 'white' }}
className={'telemetry_merger_info'}
{...other}
>
{Object.keys({ ...lables, ...info }).map(key => (
<Item
key={key}
label={lables[key] ?? key}
style={{ color: danger === true || danger?.includes(key) ? 'red' : 'black' }}
>{info?.[key] ?? '-'}</Item>
))}
</Descriptions>
))
export const TelemetryMerger = memo(() => {
const [primary, setPrimary] = useState(null)
const [secondary, setSecondary] = useState(null)
const [telemetry, setTelemetry] = useState([])
const [isLoading, setIsLoading] = useState(false)
const [isMerging, setIsMerging] = useState(false)
const location = useLocation()
const danger = useMemo(() => [
primary?.info?.well !== secondary?.info?.well && 'well',
primary?.info?.cluster !== secondary?.info?.cluster && 'cluster',
primary?.info?.deposit !== secondary?.info?.deposit && 'deposit',
], [primary, secondary])
const updateTelemetry = useCallback(async () => await invokeWebApiWrapperAsync(
async () => {
const telemetry = arrayOrDefault(await AdminTelemetryService.getAll())
setTelemetry(telemetry)
},
setIsLoading,
'Не удалось загрузить список телеметрий',
'Получение списка телеметрий',
), [])
const mergeTelemetry = useCallback(() => invokeWebApiWrapperAsync(
async () => {
await new Promise(res => setTimeout(res, 1000))
/// await AdminTelemetryService.mergeTelemetries(secondary.id, primary.id)
await updateTelemetry()
},
setIsMerging,
'Не удалось объединить телеметрии',
'Объединение телеметрий',
), [primary, secondary])
useEffect(() => updateTelemetry(), [])
useEffect(() => {
const query = new URLSearchParams(location.search)
const primaryId = parseInt(query.get('primary') ?? null)
const secondaryId = parseInt(query.get('secondary') ?? null)
const primary = isNaN(primaryId) ? null : telemetry.find((t) => t.id === primaryId)
const secondary = isNaN(secondaryId) ? null : telemetry.find((t) => t.id === secondaryId)
console.log([primary, secondary])
setPrimary(primary)
setSecondary(secondary)
}, [location, telemetry])
return (
<LoaderPortal show={isLoading}>
<div className={'description'} style={{ marginTop: '15px' }}>{
///TODO: Добавить описание
}</div>
<Grid>
<GridItem col={1} row={1}>Результирующая телеметрия</GridItem>
<GridItem col={2} row={1}>Исходная телеметрия</GridItem>
<GridItem col={1} row={2}>
<TelemetrySelect
value={primary}
disabled={isMerging}
telemetry={telemetry}
onChange={setPrimary}
style={{ width: '100%', marginRight: '15px' }}
/>
</GridItem>
<GridItem col={2} row={2}>
<TelemetrySelect
value={secondary}
disabled={isMerging}
telemetry={telemetry}
onChange={setSecondary}
style={{ width: '100%' }}
/>
</GridItem>
<GridItem col={3} row={2}>
<Popconfirm
disabled={isMerging || !primary || !secondary}
title={'Исходная телеметрия будет удалена после объединения. Вы уверены?'}
okText={'Объединить'}
onConfirm={mergeTelemetry}
>
<Button
type={'primary'}
icon={<PullRequestOutlined />}
disabled={!primary || !secondary}
loading={isMerging}
>Объединить</Button>
</Popconfirm>
</GridItem>
<GridItem col={1} row={3}>
<TelemetryInfo info={primary?.info} danger={danger} />
</GridItem>
<GridItem col={2} row={3}>
<TelemetryInfo info={secondary?.info} danger={danger} />
</GridItem>
</Grid>
</LoaderPortal>
)
})
export default TelemetryMerger

View File

@ -1,19 +1,55 @@
import { memo, useEffect, useMemo, useState } from 'react'
import { Input } from 'antd'
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
import { PullRequestOutlined } from '@ant-design/icons'
import { Button, Input } from 'antd'
import {
defaultPagination,
makeColumn,
makeDateSorter,
makeNumericColumn,
makeNumericRender,
makeTextColumn,
Table
} from '@components/Table'
import Poprompt from '@components/selectors/Poprompt'
import { invokeWebApiWrapperAsync } from '@components/factory'
import { AdminTelemetryService } from '@api'
import { arrayOrDefault } from '@utils'
import { useHistory } from 'react-router-dom'
const columns = [
export const TelemetryController = memo(() => {
const [telemetryData, setTelemetryData] = useState([])
const [showLoader, setShowLoader] = useState(false)
const [searchValue, setSearchValue] = useState('')
const history = useHistory()
const toMerger = useCallback((type, id) => () => history.push(`/admin/telemetry/merger/?${type}=${id}`), [history])
const mergeRender = useCallback((value, record) => (
<Poprompt
placement={'topLeft'}
buttonProps={{
icon: <PullRequestOutlined />,
size: 'small',
danger: !!value,
}}
footer={(
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Button onClick={toMerger('primary', record.id)}>Основная</Button>
<Button onClick={toMerger('secondary', record.id)} style={{ marginLeft: '8px' }}>Сливаемая</Button>
</div>
)}
>
<p>Вы собираетесь использовать данную телеметрию для слияния</p>
{record.well && (
<p style={{ color: 'red' }}>Внимание! Телеметрии назначена скважина!</p>
)}
</Poprompt>
), [toMerger])
const columns = useMemo(() => [
makeColumn('', 'hasParent', { render: mergeRender }),
makeNumericColumn('ID', 'id', null, null, makeNumericRender(0)),
makeTextColumn('UID', 'remoteUid'),
makeTextColumn('Назначена на скважину', 'realWell'),
@ -27,12 +63,7 @@ const columns = [
makeTextColumn('Версия HMI', 'hmiVersion'),
makeTextColumn('Версия САУБ', 'saubPlcVersion'),
makeTextColumn('Версия Спин Мастер', 'spinPlcVersion'),
]
export const TelemetryController = memo(() => {
const [telemetryData, setTelemetryData] = useState([])
const [showLoader, setShowLoader] = useState(false)
const [searchValue, setSearchValue] = useState('')
], [mergeRender])
const filteredTelemetryData = useMemo(() => telemetryData.filter((telemetry) => telemetry && (!searchValue || [
telemetry.id?.toString() ?? '',

View File

@ -0,0 +1,42 @@
import { Layout, Menu } from 'antd'
import { lazy, memo, Suspense } from 'react'
import { Switch, useParams } from 'react-router-dom'
import { PrivateMenuItem, PrivateRoute, PrivateDefaultRoute } from '@components/Private'
import { SuspenseFallback } from '@pages/SuspenseFallback'
const TelemetryViewer = lazy(() => import('./TelemetryViewer'))
const TelemetryMerger = lazy(() => import('./TelemetryMerger'))
const rootPath = '/admin/telemetry'
export const Telemetry = memo(() => {
const { tab } = useParams()
return (
<Layout>
<Menu mode={'horizontal'} selectable={true} selectedKeys={[tab]}>
<PrivateMenuItem.Link root={rootPath} key={'viewer'} path={'viewer'} title={'Просмотр'} />
<PrivateMenuItem.Link root={rootPath} key={'merger'} path={'merger'} title={'Объединение'} />
</Menu>
<Layout>
<Layout.Content className={'site-layout-background'}>
<Suspense fallback={<SuspenseFallback />}>
<Switch>
<PrivateRoute path={`${rootPath}/viewer`} component={TelemetryViewer} />
<PrivateRoute path={`${rootPath}/merger`} component={TelemetryMerger} />
<PrivateDefaultRoute urls={[
`${rootPath}/viewer`,
`${rootPath}/merger`,
]}/>
</Switch>
</Suspense>
</Layout.Content>
</Layout>
</Layout>
)
})
export default Telemetry

View File

@ -1,5 +1,5 @@
import { Layout, Menu } from 'antd'
import { lazy, Suspense } from 'react'
import { lazy, memo, Suspense } from 'react'
import { Switch, useParams } from 'react-router-dom'
import { PrivateMenuItem, PrivateRoute, PrivateDefaultRoute } from '@components/Private'
@ -14,12 +14,12 @@ const WellController = lazy(() => import( './WellController'))
const RoleController = lazy(() => import( './RoleController'))
const CompanyTypeController = lazy(() => import('./CompanyTypeController'))
const PermissionController = lazy(() => import( './PermissionController'))
const TelemetryController = lazy(() => import( './TelemetryController'))
const TelemetrySection = lazy(() => import( './Telemetry'))
const VisitLog = lazy(() => import( './VisitLog'))
const rootPath = '/admin'
export const AdminPanel = () => {
export const AdminPanel = memo(() => {
const { tab } = useParams()
return (
@ -33,7 +33,7 @@ export const AdminPanel = () => {
<PrivateMenuItem.Link root={rootPath} key={'company_type'} path={'company_type'} title={'Типы компаний' } />
<PrivateMenuItem.Link root={rootPath} key={'role' } path={'role' } title={'Роли' } />
<PrivateMenuItem.Link root={rootPath} key={'permission' } path={'permission' } title={'Разрешения' } />
<PrivateMenuItem.Link root={rootPath} key={'telemetry' } path={'telemetry' } title={'Телеметрии' } />
<PrivateMenuItem.Link root={rootPath} key={'telemetry' } path={'telemetry' } title={'Телеметрия' } />
<PrivateMenuItem.Link root={rootPath} key={'visit_log' } path={'visit_log' } title={'Журнал посещений'} />
</Menu>
@ -46,10 +46,10 @@ export const AdminPanel = () => {
<PrivateRoute path={`${rootPath}/well` } component={ WellController} />
<PrivateRoute path={`${rootPath}/user` } component={ UserController} />
<PrivateRoute path={`${rootPath}/company` } component={ CompanyController} />
<PrivateRoute path={`${rootPath}/company_type`} component={CompanyTypeController} />
<PrivateRoute path={`${rootPath}/company_type` } component={CompanyTypeController} />
<PrivateRoute path={`${rootPath}/role` } component={ RoleController} />
<PrivateRoute path={`${rootPath}/permission` } component={ PermissionController} />
<PrivateRoute path={`${rootPath}/telemetry` } component={ TelemetryController} />
<PrivateRoute path={`${rootPath}/telemetry/:tab?`} component={TelemetrySection} />
<PrivateRoute path={`${rootPath}/visit_log` } component={VisitLog} />
<PrivateDefaultRoute urls={[
`${rootPath}/deposit`,
@ -69,6 +69,6 @@ export const AdminPanel = () => {
</Layout>
</Layout>
)
}
})
export default AdminPanel

View File

@ -78,7 +78,10 @@ export const requirements: PermissionRecord = {
permission: ['AdminPermission.get'],
role: ['AdminUserRole.get', 'AdminPermission.get'],
visit_log: ['RequerstTracker.get'],
telemetry: ['AdminTelemetry.get'],
telemetry: {
merger: ['AdminTelemetry.get'],
viewer: ['AdminTelemetry.get'],
},
},
deposit: ['Deposit.get', 'Cluster.get'],
cluster: {