forked from ddrilling/asb_cloud_front
* Улучшено отображение пончиковой диаграммы
* Добавлены кнопки выгрузки операций
This commit is contained in:
parent
ba843f0fde
commit
f8f4d8f90b
@ -14,15 +14,16 @@ export const NetGraphExport = memo(({ idWell, ...other }) => {
|
||||
), [idWell])
|
||||
|
||||
return (
|
||||
<Button
|
||||
icon={<ExportOutlined />}
|
||||
loading={isFileExporting}
|
||||
onClick={onExport}
|
||||
style={{ marginRight: '5px' }}
|
||||
{...other}
|
||||
>
|
||||
Сетевой график
|
||||
</Button>
|
||||
<div className={'tvd-input-group'}>
|
||||
<Button
|
||||
icon={<ExportOutlined />}
|
||||
loading={isFileExporting}
|
||||
onClick={onExport}
|
||||
{...other}
|
||||
>
|
||||
Сетевой график
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
|
38
src/pages/WellOperations/Tvd/StatExport.jsx
Normal file
38
src/pages/WellOperations/Tvd/StatExport.jsx
Normal file
@ -0,0 +1,38 @@
|
||||
import { memo, useCallback, useEffect, useState } from 'react'
|
||||
import { Button, Input } from 'antd'
|
||||
|
||||
import { useIdWell } from '@asb/context'
|
||||
import { download, invokeWebApiWrapperAsync } from '@components/factory'
|
||||
import { WellService } from '@api'
|
||||
|
||||
export const StatExport = memo(() => {
|
||||
const [isFileExporting, setIsFileExporting] = useState(false)
|
||||
const [idCluster, setIdCluster] = useState()
|
||||
const idWell = useIdWell()
|
||||
|
||||
useEffect(() => {
|
||||
invokeWebApiWrapperAsync(
|
||||
async () => {
|
||||
const { idCluster } = await WellService.get(idWell)
|
||||
setIdCluster(idCluster)
|
||||
},
|
||||
setIsFileExporting,
|
||||
'Не удалось загрузить ID куста'
|
||||
)
|
||||
}, [idWell])
|
||||
|
||||
const onExport = useCallback((well) => invokeWebApiWrapperAsync(
|
||||
async () => await download(`/api/DetectedOperation/export?${well ? 'idWell' : 'idCluster'}=${well ? idWell : idCluster}`),
|
||||
setIsFileExporting,
|
||||
'Не удалось загрузить файл'
|
||||
), [idWell, idCluster])
|
||||
|
||||
return (
|
||||
<Input.Group compact>
|
||||
<Button loading={isFileExporting} onClick={() => onExport(false)}>Выгрузка (куст)</Button>
|
||||
<Button loading={isFileExporting} onClick={() => onExport(true)}>Выгрузка (скважина)</Button>
|
||||
</Input.Group>
|
||||
)
|
||||
})
|
||||
|
||||
export default StatExport
|
@ -4,10 +4,21 @@ import { Empty } from 'antd'
|
||||
import * as d3 from 'd3'
|
||||
|
||||
import { useIdWell } from '@asb/context'
|
||||
import { makeColumn, makeNumericColumn, makeTextColumn, Table } from '@components/Table'
|
||||
import LoaderPortal from '@components/LoaderPortal'
|
||||
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||
import { DetectedOperationService } from '@api'
|
||||
|
||||
const tableColumns = [
|
||||
makeColumn('Цвет', 'color', { width: 50, render: (d) => (
|
||||
<div style={{ backgroundColor: d, padding: '5px 0' }} />
|
||||
) }),
|
||||
makeTextColumn('Название', 'category', undefined, undefined, undefined, { width: 300 }),
|
||||
makeNumericColumn('Время, мин', 'minutesTotal', undefined, undefined, undefined, 100),
|
||||
makeNumericColumn('Кол-во', 'count', undefined, undefined, (d) => d ? d.toString() : '---', 100),
|
||||
makeNumericColumn('Процент, %', 'percent', undefined, undefined, (d) => d ? d.toFixed(2) : '---', 100)
|
||||
]
|
||||
|
||||
export const TLPie = memo(({ color }) => {
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [svgRef, setSvgRef] = useState()
|
||||
@ -17,10 +28,21 @@ export const TLPie = memo(({ color }) => {
|
||||
|
||||
const idWell = useIdWell()
|
||||
|
||||
const pie = useMemo(() => d3.pie().value((d) => d.count), [])
|
||||
const data = useMemo(() => stats ? pie(stats) : null, [stats, pie])
|
||||
const pie = useMemo(() => d3.pie().value((d) => d.minutesTotal), [])
|
||||
|
||||
const radius = useMemo(() => Math.min(width, height) / 2 - 100, [width, height])
|
||||
const tableData = useMemo(() => {
|
||||
if (!stats) return null
|
||||
const totalTime = stats.reduce((out, stat) => out + stat.minutesTotal, 0)
|
||||
return stats.map((stat) => ({
|
||||
...stat,
|
||||
color: color(stat.idCategory),
|
||||
percent: stat.minutesTotal / totalTime * 100,
|
||||
}))
|
||||
}, [stats, color])
|
||||
|
||||
const data = useMemo(() => tableData ? pie(tableData) : null, [tableData])
|
||||
|
||||
const radius = useMemo(() => Math.min(width, height) / 2, [width, height])
|
||||
|
||||
useEffect(() => {
|
||||
invokeWebApiWrapperAsync(
|
||||
@ -88,21 +110,32 @@ export const TLPie = memo(({ color }) => {
|
||||
})
|
||||
.style('text-anchor', (d) => abovePi(d) ? 'start' : 'end')
|
||||
.attr('width', radius * 0.4)
|
||||
.text((d) => `${d.data.category} (${d.data.count})`)
|
||||
.text((d) => `${d.data.percent.toFixed(2)}% (${d.data.minutesTotal.toFixed(2)} мин)`)
|
||||
|
||||
}, [svgRef, data, radius])
|
||||
|
||||
return (
|
||||
<div ref={rootRef} className={'tvd-right'}>
|
||||
<div className={'tvd-right'}>
|
||||
<LoaderPortal show={isLoading} style={{ width: '100%', flexGrow: 1 }}>
|
||||
{data ? (
|
||||
<svg ref={setSvgRef} style={{ width: '100%', height: '100%' }}>
|
||||
<g transform={`translate(${width / 2}, ${height / 2})`}>
|
||||
<g className={'slices'} stroke={'#0005'} />
|
||||
<g className={'labels'} fill={'black'} />
|
||||
<g className={'lines'} fill={'none'} stroke={'black'} />
|
||||
</g>
|
||||
</svg>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'stretch', justifyContent: 'space-between', height: '100%' }}>
|
||||
<div ref={rootRef} style={{ flexGrow: 1 }}>
|
||||
<svg ref={setSvgRef} width={'100%'} height={'100%'}>
|
||||
<g transform={`translate(${width / 2}, ${height / 2})`}>
|
||||
<g className={'slices'} stroke={'#0005'} />
|
||||
<g className={'labels'} fill={'black'} />
|
||||
<g className={'lines'} fill={'none'} stroke={'black'} />
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<Table
|
||||
size={'small'}
|
||||
columns={tableColumns}
|
||||
dataSource={tableData}
|
||||
scroll={{ y: '20vh', x: true }}
|
||||
pagination={false}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ height: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
||||
<Empty />
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { LineChartOutlined, LinkOutlined } from '@ant-design/icons'
|
||||
import { memo, useState, useEffect, useMemo } from 'react'
|
||||
import { Switch, Segmented } from 'antd'
|
||||
import { Switch, Segmented, Button } from 'antd'
|
||||
import { Link } from 'react-router-dom'
|
||||
import * as d3 from 'd3'
|
||||
|
||||
@ -14,6 +14,7 @@ import { DetectedOperationService } from '@api'
|
||||
import TLPie from './TLPie'
|
||||
import TLChart from './TLChart'
|
||||
import NptTable from './NptTable'
|
||||
import StatExport from './StatExport'
|
||||
import NetGraphExport from './NetGraphExport'
|
||||
import AdditionalTables from './AdditionalTables'
|
||||
|
||||
@ -21,8 +22,10 @@ import '@styles/index.css'
|
||||
import '@styles/tvd.less'
|
||||
|
||||
const colorArray = [
|
||||
'#1abc9c', '#16a085', '#2ecc71', '#27ae60', '#3498db', '#2980b9', '#9b59b6', '#8e44ad', '#34495e', '#2c3e50',
|
||||
'#f1c40f', '#f39c12', '#e67e22', '#d35400', '#e74c3c', '#c0392b', '#ecf0f1', '#bdc3c7', '#95a5a6', '#7f8c8d',
|
||||
'#1abc9c', '#16a085', '#2ecc71', '#27ae60', '#3498db',
|
||||
'#2980b9', '#9b59b6', '#8e44ad', '#34495e', '#2c3e50',
|
||||
'#f1c40f', '#f39c12', '#e67e22', '#d35400', '#e74c3c',
|
||||
'#c0392b', '#ecf0f1', '#bdc3c7', '#95a5a6', '#7f8c8d',
|
||||
]
|
||||
|
||||
const Item = ({ label, children, ...other }) => (<div className={'tvd-input-group'} {...other}><span>{label}: </span>{children}</div>)
|
||||
@ -222,6 +225,7 @@ const Tvd = memo(({ idWell: wellId, title, ...other }) => {
|
||||
</Item>
|
||||
</div>
|
||||
<div className={'tvd-inputs'}>
|
||||
<StatExport />
|
||||
<NetGraphExport idWell={idWell} />
|
||||
<Segmented
|
||||
options={['НПВ', 'ЕСО', 'Статистика', 'Скрыть']}
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
.tvd-top {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 20px;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user