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 { Grid, GridItem } from '@components/Grid'
|
||||
|
||||
const lables: Record<string, string> = {
|
||||
export const lables: Record<string, string> = {
|
||||
timeZoneId: 'Временная зона',
|
||||
timeZoneOffsetTotalHours: 'Сдвиг временной зоны',
|
||||
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 { 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'
|
||||
|
||||
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'),
|
||||
]
|
||||
import { useHistory } from 'react-router-dom'
|
||||
|
||||
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'),
|
||||
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 || [
|
||||
telemetry.id?.toString() ?? '',
|
||||
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 { 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>
|
||||
|
||||
@ -41,16 +41,16 @@ export const AdminPanel = () => {
|
||||
<Layout.Content className={'site-layout-background'}>
|
||||
<Suspense fallback={<SuspenseFallback />}>
|
||||
<Switch>
|
||||
<PrivateRoute path={`${rootPath}/deposit` } component={ DepositController} />
|
||||
<PrivateRoute path={`${rootPath}/cluster` } component={ ClusterController} />
|
||||
<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}/role` } component={ RoleController} />
|
||||
<PrivateRoute path={`${rootPath}/permission` } component={ PermissionController} />
|
||||
<PrivateRoute path={`${rootPath}/telemetry` } component={ TelemetryController} />
|
||||
<PrivateRoute path={`${rootPath}/visit_log` } component={VisitLog} />
|
||||
<PrivateRoute path={`${rootPath}/deposit` } component={ DepositController} />
|
||||
<PrivateRoute path={`${rootPath}/cluster` } component={ ClusterController} />
|
||||
<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}/role` } component={ RoleController} />
|
||||
<PrivateRoute path={`${rootPath}/permission` } component={ PermissionController} />
|
||||
<PrivateRoute path={`${rootPath}/telemetry/:tab?`} component={TelemetrySection} />
|
||||
<PrivateRoute path={`${rootPath}/visit_log` } component={VisitLog} />
|
||||
<PrivateDefaultRoute urls={[
|
||||
`${rootPath}/deposit`,
|
||||
`${rootPath}/cluster`,
|
||||
@ -69,6 +69,6 @@ export const AdminPanel = () => {
|
||||
</Layout>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
export default AdminPanel
|
||||
|
@ -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: {
|
||||
|
Loading…
Reference in New Issue
Block a user