forked from ddrilling/asb_cloud_front
В телеметрию админ-панели добавлена страница объединения, добавлены кнопки на странице просмотра для перехода к объединению
This commit is contained in:
parent
c2eac25470
commit
befac57c30
@ -4,7 +4,7 @@ import { Tooltip } from 'antd'
|
|||||||
import { TelemetryDto, TelemetryInfoDto } from '@api'
|
import { TelemetryDto, TelemetryInfoDto } from '@api'
|
||||||
import { Grid, GridItem } from '@components/Grid'
|
import { Grid, GridItem } from '@components/Grid'
|
||||||
|
|
||||||
const lables: Record<string, string> = {
|
export const lables: Record<string, string> = {
|
||||||
timeZoneId: 'Временная зона',
|
timeZoneId: 'Временная зона',
|
||||||
timeZoneOffsetTotalHours: 'Сдвиг временной зоны',
|
timeZoneOffsetTotalHours: 'Сдвиг временной зоны',
|
||||||
drillingStartDate: 'Начало бурения',
|
drillingStartDate: 'Начало бурения',
|
||||||
|
136
src/pages/AdminPanel/Telemetry/TelemetryMerger.jsx
Normal file
136
src/pages/AdminPanel/Telemetry/TelemetryMerger.jsx
Normal 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
|
@ -1,39 +1,70 @@
|
|||||||
import { memo, useEffect, useMemo, useState } from 'react'
|
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
import { Input } from 'antd'
|
import { PullRequestOutlined } from '@ant-design/icons'
|
||||||
|
import { Button, Input } from 'antd'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
defaultPagination,
|
defaultPagination,
|
||||||
|
makeColumn,
|
||||||
makeDateSorter,
|
makeDateSorter,
|
||||||
makeNumericColumn,
|
makeNumericColumn,
|
||||||
makeNumericRender,
|
makeNumericRender,
|
||||||
makeTextColumn,
|
makeTextColumn,
|
||||||
Table
|
Table
|
||||||
} from '@components/Table'
|
} from '@components/Table'
|
||||||
|
import Poprompt from '@components/selectors/Poprompt'
|
||||||
import { invokeWebApiWrapperAsync } from '@components/factory'
|
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||||
import { AdminTelemetryService } from '@api'
|
import { AdminTelemetryService } from '@api'
|
||||||
import { arrayOrDefault } from '@utils'
|
import { arrayOrDefault } from '@utils'
|
||||||
|
import { useHistory } from 'react-router-dom'
|
||||||
const columns = [
|
|
||||||
makeNumericColumn('ID', 'id', null, null, makeNumericRender(0)),
|
|
||||||
makeTextColumn('UID', 'remoteUid'),
|
|
||||||
makeTextColumn('Назначена на скважину', 'realWell'),
|
|
||||||
makeTextColumn('Дата начала бурения', 'drillingStartDate', null, makeDateSorter('drillingStartDate')),
|
|
||||||
makeTextColumn('Часовой пояс', 'timeZoneId'),
|
|
||||||
makeTextColumn('Скважина', 'well'),
|
|
||||||
makeTextColumn('Куст', 'cluster'),
|
|
||||||
makeTextColumn('Месторождение', 'deposit'),
|
|
||||||
makeTextColumn('Заказчик', 'customer'),
|
|
||||||
makeTextColumn('Комментарий', 'comment'),
|
|
||||||
makeTextColumn('Версия HMI', 'hmiVersion'),
|
|
||||||
makeTextColumn('Версия САУБ', 'saubPlcVersion'),
|
|
||||||
makeTextColumn('Версия Спин Мастер', 'spinPlcVersion'),
|
|
||||||
]
|
|
||||||
|
|
||||||
export const TelemetryController = memo(() => {
|
export const TelemetryController = memo(() => {
|
||||||
const [telemetryData, setTelemetryData] = useState([])
|
const [telemetryData, setTelemetryData] = useState([])
|
||||||
const [showLoader, setShowLoader] = useState(false)
|
const [showLoader, setShowLoader] = useState(false)
|
||||||
const [searchValue, setSearchValue] = useState('')
|
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'),
|
||||||
|
makeTextColumn('Дата начала бурения', 'drillingStartDate', null, makeDateSorter('drillingStartDate')),
|
||||||
|
makeTextColumn('Часовой пояс', 'timeZoneId'),
|
||||||
|
makeTextColumn('Скважина', 'well'),
|
||||||
|
makeTextColumn('Куст', 'cluster'),
|
||||||
|
makeTextColumn('Месторождение', 'deposit'),
|
||||||
|
makeTextColumn('Заказчик', 'customer'),
|
||||||
|
makeTextColumn('Комментарий', 'comment'),
|
||||||
|
makeTextColumn('Версия HMI', 'hmiVersion'),
|
||||||
|
makeTextColumn('Версия САУБ', 'saubPlcVersion'),
|
||||||
|
makeTextColumn('Версия Спин Мастер', 'spinPlcVersion'),
|
||||||
|
], [mergeRender])
|
||||||
|
|
||||||
const filteredTelemetryData = useMemo(() => telemetryData.filter((telemetry) => telemetry && (!searchValue || [
|
const filteredTelemetryData = useMemo(() => telemetryData.filter((telemetry) => telemetry && (!searchValue || [
|
||||||
telemetry.id?.toString() ?? '',
|
telemetry.id?.toString() ?? '',
|
||||||
telemetry.remoteUid ?? '',
|
telemetry.remoteUid ?? '',
|
42
src/pages/AdminPanel/Telemetry/index.jsx
Normal file
42
src/pages/AdminPanel/Telemetry/index.jsx
Normal 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
|
@ -1,5 +1,5 @@
|
|||||||
import { Layout, Menu } from 'antd'
|
import { Layout, Menu } from 'antd'
|
||||||
import { lazy, Suspense } from 'react'
|
import { lazy, memo, Suspense } from 'react'
|
||||||
import { Switch, useParams } from 'react-router-dom'
|
import { Switch, useParams } from 'react-router-dom'
|
||||||
|
|
||||||
import { PrivateMenuItem, PrivateRoute, PrivateDefaultRoute } from '@components/Private'
|
import { PrivateMenuItem, PrivateRoute, PrivateDefaultRoute } from '@components/Private'
|
||||||
@ -14,12 +14,12 @@ const WellController = lazy(() => import( './WellController'))
|
|||||||
const RoleController = lazy(() => import( './RoleController'))
|
const RoleController = lazy(() => import( './RoleController'))
|
||||||
const CompanyTypeController = lazy(() => import('./CompanyTypeController'))
|
const CompanyTypeController = lazy(() => import('./CompanyTypeController'))
|
||||||
const PermissionController = lazy(() => import( './PermissionController'))
|
const PermissionController = lazy(() => import( './PermissionController'))
|
||||||
const TelemetryController = lazy(() => import( './TelemetryController'))
|
const TelemetrySection = lazy(() => import( './Telemetry'))
|
||||||
const VisitLog = lazy(() => import( './VisitLog'))
|
const VisitLog = lazy(() => import( './VisitLog'))
|
||||||
|
|
||||||
const rootPath = '/admin'
|
const rootPath = '/admin'
|
||||||
|
|
||||||
export const AdminPanel = () => {
|
export const AdminPanel = memo(() => {
|
||||||
const { tab } = useParams()
|
const { tab } = useParams()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -33,7 +33,7 @@ export const AdminPanel = () => {
|
|||||||
<PrivateMenuItem.Link root={rootPath} key={'company_type'} path={'company_type'} title={'Типы компаний' } />
|
<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={'role' } path={'role' } title={'Роли' } />
|
||||||
<PrivateMenuItem.Link root={rootPath} key={'permission' } path={'permission' } 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={'Журнал посещений'} />
|
<PrivateMenuItem.Link root={rootPath} key={'visit_log' } path={'visit_log' } title={'Журнал посещений'} />
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
@ -41,16 +41,16 @@ export const AdminPanel = () => {
|
|||||||
<Layout.Content className={'site-layout-background'}>
|
<Layout.Content className={'site-layout-background'}>
|
||||||
<Suspense fallback={<SuspenseFallback />}>
|
<Suspense fallback={<SuspenseFallback />}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<PrivateRoute path={`${rootPath}/deposit` } component={ DepositController} />
|
<PrivateRoute path={`${rootPath}/deposit` } component={ DepositController} />
|
||||||
<PrivateRoute path={`${rootPath}/cluster` } component={ ClusterController} />
|
<PrivateRoute path={`${rootPath}/cluster` } component={ ClusterController} />
|
||||||
<PrivateRoute path={`${rootPath}/well` } component={ WellController} />
|
<PrivateRoute path={`${rootPath}/well` } component={ WellController} />
|
||||||
<PrivateRoute path={`${rootPath}/user` } component={ UserController} />
|
<PrivateRoute path={`${rootPath}/user` } component={ UserController} />
|
||||||
<PrivateRoute path={`${rootPath}/company` } component={ CompanyController} />
|
<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}/role` } component={ RoleController} />
|
||||||
<PrivateRoute path={`${rootPath}/permission` } component={ PermissionController} />
|
<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} />
|
<PrivateRoute path={`${rootPath}/visit_log` } component={VisitLog} />
|
||||||
<PrivateDefaultRoute urls={[
|
<PrivateDefaultRoute urls={[
|
||||||
`${rootPath}/deposit`,
|
`${rootPath}/deposit`,
|
||||||
`${rootPath}/cluster`,
|
`${rootPath}/cluster`,
|
||||||
@ -69,6 +69,6 @@ export const AdminPanel = () => {
|
|||||||
</Layout>
|
</Layout>
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
})
|
||||||
|
|
||||||
export default AdminPanel
|
export default AdminPanel
|
||||||
|
@ -78,7 +78,10 @@ export const requirements: PermissionRecord = {
|
|||||||
permission: ['AdminPermission.get'],
|
permission: ['AdminPermission.get'],
|
||||||
role: ['AdminUserRole.get', 'AdminPermission.get'],
|
role: ['AdminUserRole.get', 'AdminPermission.get'],
|
||||||
visit_log: ['RequerstTracker.get'],
|
visit_log: ['RequerstTracker.get'],
|
||||||
telemetry: ['AdminTelemetry.get'],
|
telemetry: {
|
||||||
|
merger: ['AdminTelemetry.get'],
|
||||||
|
viewer: ['AdminTelemetry.get'],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
deposit: ['Deposit.get', 'Cluster.get'],
|
deposit: ['Deposit.get', 'Cluster.get'],
|
||||||
cluster: {
|
cluster: {
|
||||||
|
Loading…
Reference in New Issue
Block a user