diff --git a/package.json b/package.json
index 576e207..13399cb 100644
--- a/package.json
+++ b/package.json
@@ -32,7 +32,7 @@
"react_test": "react-scripts test",
"eject": "react-scripts eject"
},
- "proxy": "http://192.168.1.70:5000",
+ "proxy": "http://192.168.1.58:5000",
"eslintConfig": {
"extends": [
"react-app",
diff --git a/src/components/ErrorFetch.js b/src/components/ErrorFetch.js
new file mode 100644
index 0000000..5f4cdbd
--- /dev/null
+++ b/src/components/ErrorFetch.js
@@ -0,0 +1,7 @@
+export class ErrorFetch extends Error {
+ constructor(status, message) {
+ super(message);
+ this.name = "ErrorFetch"
+ this.status = status
+ }
+}
\ No newline at end of file
diff --git a/src/components/Table/index.ts b/src/components/Table/index.tsx
similarity index 83%
rename from src/components/Table/index.ts
rename to src/components/Table/index.tsx
index 8575a03..a4d6dc5 100644
--- a/src/components/Table/index.ts
+++ b/src/components/Table/index.tsx
@@ -1,4 +1,6 @@
import { ReactNode } from 'react'
+import { makeNumericSorter, makeStringSorter} from './sorters'
+export { makeDateSorter, makeNumericSorter, makeStringSorter} from './sorters'
export { Table } from 'antd'
export { EditableTable } from './EditableTable'
export { DatePickerWrapper } from './DatePickerWrapper'
@@ -7,10 +9,28 @@ export { SelectFromDictionary } from './SelectFromDictionary'
export const RegExpIsFloat = /^[-+]?\d+\.?\d*$/
export const formatDate='YYYY.MM.DD HH:mm'
-export const numericColumnOptions = {
+export const makeNumericRender = (fixed?:number) => (value: any, row: object): ReactNode => {
+ const placeholder = '-'
+ let val = placeholder
+ if((value !== null) ||
+ (value !== undefined) ||
+ Number.isNaN(value) ||
+ !Number.isFinite(value)){
+ val = !!fixed
+ ? (+value).toFixed(fixed)
+ : (+value).toPrecision(5)
+ }
+
+ return (
+ {val}
+
)
+}
+
+export const makeNumericColumnOptions = (fixed?:number, sorterKey?:string ) => ({
editable: true,
initialValue: 0,
width:100,
+ sorter: sorterKey? makeNumericSorter(sorterKey) : null,
formItemRules: [
{
required: true,
@@ -18,7 +38,8 @@ export const numericColumnOptions = {
pattern: RegExpIsFloat,
},
],
-};
+ render: makeNumericRender(fixed),
+})
/*
other - объект с дополнительными свойствами колонки
@@ -78,41 +99,6 @@ export const makeColumnsPlanFact = (title:string | ReactNode, key:string|string[
export const makeFilterTextMatch = (key: string | number) => (filterValue: string | number, dataItem: any) =>
dataItem[key] === filterValue
-export const makeNumericSorter = (key: string) => (a: any, b: any) => a[key] - b[key]
-
-export const makeStringSorter = (key: string) => (a: any, b: any) =>
-{
- if(a == null && b == null)
- return 1
-
- if(a == null)
- return 1
-
- if(b == null)
- return -1
-
- let aValue = a[key]
- let bValue = b[key]
-
- for (let i = 0; i < a.length; i++) {
- if (isNaN(aValue.charCodeAt(i)) || (aValue.charCodeAt(i) > bValue.charCodeAt(i)))
- return 1
-
- if (aValue.charCodeAt(i) > bValue.charCodeAt(i))
- return -1
- }
- return 0
-}
-
-export const makeDateSorter = (key: string) => (a: any, b: any) => {
- const date = new Date(a[key])
-
- if(Number.isNaN(date.getTime()))
- throw new Error('Date column contains not date formatted string(s)')
-
- return date.getTime() - new Date(b[key]).getTime()
-}
-
export const makeGroupColumn = (title: string, children: object[]) => ({
title: title,
children: children,
@@ -135,17 +121,6 @@ export const makeTextColumn = (
...other
})
-export const defaultNumericRender = (value: any, row: object) => {
- const placeholder = '-'
- if((value === null) ||
- (value === undefined) ||
- Number.isNaN(value) ||
- !Number.isFinite(value))
- return placeholder
-
- return (+value).toPrecision(5)
-}
-
export const makeNumericColumn = (title: string, dataIndex: string,
filters: object[], filterDelegate: (key: string | number) => any,
renderDelegate: (_: any, row: object) => any, width: string, other?: columnPropsOther) => ({
@@ -156,7 +131,7 @@ export const makeNumericColumn = (title: string, dataIndex: string,
onFilter: filterDelegate ? filterDelegate(dataIndex) : null,
sorter: makeNumericSorter(dataIndex),
width: width,
- render: renderDelegate??defaultNumericRender,
+ render: renderDelegate??makeNumericRender(),
align: 'right',
...other
})
diff --git a/src/components/Table/sorters.ts b/src/components/Table/sorters.ts
new file mode 100644
index 0000000..71732cb
--- /dev/null
+++ b/src/components/Table/sorters.ts
@@ -0,0 +1,33 @@
+export const makeNumericSorter = (key: string) => (a: any, b: any) => a[key] - b[key];
+
+export const makeStringSorter = (key: string) => (a: any, b: any) => {
+ if (a == null && b == null)
+ return 1;
+
+ if (a == null)
+ return 1;
+
+ if (b == null)
+ return -1;
+
+ let aValue = a[key];
+ let bValue = b[key];
+
+ for (let i = 0; i < a.length; i++) {
+ if (isNaN(aValue.charCodeAt(i)) || (aValue.charCodeAt(i) > bValue.charCodeAt(i)))
+ return 1;
+
+ if (aValue.charCodeAt(i) > bValue.charCodeAt(i))
+ return -1;
+ }
+ return 0;
+};
+
+export const makeDateSorter = (key: string) => (a: any, b: any) => {
+ const date = new Date(a[key]);
+
+ if (Number.isNaN(date.getTime()))
+ throw new Error('Date column contains not date formatted string(s)');
+
+ return date.getTime() - new Date(b[key]).getTime();
+};
diff --git a/src/components/UploadForm.jsx b/src/components/UploadForm.jsx
index 95a3055..47be967 100644
--- a/src/components/UploadForm.jsx
+++ b/src/components/UploadForm.jsx
@@ -2,22 +2,38 @@ import { Upload, Button } from 'antd'
import { UploadOutlined } from '@ant-design/icons'
import { useState } from 'react'
import { upload } from './factory'
+import { ErrorFetch } from './ErrorFetch'
-export default function UploadForm({url, accept, onUploadStart, onUploadComplete, onUploadError}) {
+export const UploadForm = ({url, accept, style, formData, onUploadStart, onUploadSuccess, onUploadComplete, onUploadError}) => {
const [fileList, setfileList] = useState([])
- const handleFileSend = async (values) => {
+ const handleFileSend = async () => {
if(onUploadStart)
onUploadStart()
try {
- const formData = new FormData()
+ const formDataLocal = new FormData()
fileList.forEach((val) => {
- formData.append("files", val.originFileObj);
- });
- await upload(url, formData)
+ formDataLocal.append("files", val.originFileObj)
+ })
+
+ if(formData)
+ for(var propName in formData)
+ formDataLocal.append(propName, formData[propName])
+
+ const response = await upload(url, formDataLocal)
+ if(!response.ok)
+ {
+ const errorText = await response.text()
+ const error = new ErrorFetch(response.status, errorText)
+ throw error
+ }
+ else{
+ if(onUploadSuccess)
+ onUploadSuccess()
+ }
} catch(error) {
if(onUploadError)
- onUploadError(error)
+ onUploadError(error)
} finally {
setfileList([])
if(onUploadComplete)
@@ -27,7 +43,7 @@ export default function UploadForm({url, accept, onUploadStart, onUploadComplete
const isSendButtonEnabled = fileList.length > 0
return(
-
+
{
Фамилия:
-
+
{user?.surname}
diff --git a/src/components/factory.ts b/src/components/factory.ts
index ca09446..6402027 100644
--- a/src/components/factory.ts
+++ b/src/components/factory.ts
@@ -81,13 +81,14 @@ export const download = async (url:string, fileName?:string) => {
}
export const upload = async (url:string, formData: FormData) => {
- await fetch(url, {
+ let response = await fetch(url, {
headers: {
Authorization: 'Bearer ' + localStorage['token']
},
method: 'Post',
body: formData,
})
+ return response
}
export const downloadFile = async (fileInfo: FileInfoDto) => {
diff --git a/src/pages/Archive.jsx b/src/pages/Archive.jsx
index 3a9f28b..cb75ad5 100644
--- a/src/pages/Archive.jsx
+++ b/src/pages/Archive.jsx
@@ -5,7 +5,7 @@ import {
Row,
Col,
Tooltip} from 'antd'
-import { DataService } from '../services/api'
+import { TelemetryDataSaubService } from '../services/api'
import {generateUUID} from '../services/UidGenerator'
import { ArchiveColumn } from '../components/ArchiveColumn'
import moment from 'moment'
@@ -94,7 +94,7 @@ export default function Archive({idWell}) {
let startDate = rangeDate[0].toISOString()
setLoader(true)
- DataService.getData(idWell, startDate, interval, 2048)
+ TelemetryDataSaubService.getData(idWell, startDate, interval, 2048)
.then(handleReceiveDataSaub)
.catch(error => {
notify(`Не удалось загрузить данные по скважине (${idWell}) c ${rangeDate[0]} по ${rangeDate[1]}`, 'error')
diff --git a/src/pages/Cluster/ClusterSections.jsx b/src/pages/Cluster/ClusterSections.jsx
index b87ecd6..f3b862b 100644
--- a/src/pages/Cluster/ClusterSections.jsx
+++ b/src/pages/Cluster/ClusterSections.jsx
@@ -7,7 +7,7 @@ import {
makeNumericColumnPlanFact
} from "../../components/Table";
import { invokeWebApiWrapperAsync } from '../../components/factory';
-import ChartDepthToDay from '../../components/charts/ChartDepthToDay';
+import ChartTvD from '../WellOperations/ChartTvD';
import WellOperationsTable from './WellOperationsTable'
import {
calcAndUpdateStatsBySections,
@@ -249,10 +249,10 @@ export default function ClusterSections({ clusterData }) {
width={1500}
footer={null}
>
-
+ dataPredict={tvdDataForecast} />
{
width={1500}
footer={null}
>
-
diff --git a/src/pages/Cluster/functions.jsx b/src/pages/Cluster/functions.jsx
index 557e867..a50358b 100644
--- a/src/pages/Cluster/functions.jsx
+++ b/src/pages/Cluster/functions.jsx
@@ -6,17 +6,24 @@ const minPrefix = "isMin"
export const getOperations = async (idWell) => {
const ops = await WellOperationStatService.getTvd(idWell);
- const planData = ops.map(el => {
- return {key: el.plan?.id, depth: el.plan?.wellDepth, date: el.plan?.startDate}
- }).filter(el => el.key)
+ const convert = wellOperationDto =>
+ ({
+ key: wellOperationDto?.id,
+ depth: wellOperationDto?.depthStart,
+ date: wellOperationDto?.dateStart
+ })
- const factData = ops.map(el => {
- return {key: el.fact?.id, depth: el.fact?.wellDepth, date: el.fact?.startDate}
- }).filter(el => el.key)
+ const planData = ops
+ .map(item => convert(item.plan))
+ .filter(el => el.key)
- const predictData = ops.map(el => {
- return {key: el.predict?.id, depth: el.predict?.wellDepth, date: el.predict?.startDate}
- }).filter(el => el.key)
+ const factData = ops
+ .map(item => convert(item.fact))
+ .filter(el => el.key)
+
+ const predictData = ops
+ .map(item => convert(item.predict))
+ .filter(el => el.key)
return { operations: ops, plan: planData, fact: factData, predict: predictData }
}
diff --git a/src/pages/Documents/DocumentsTemplate.jsx b/src/pages/Documents/DocumentsTemplate.jsx
index 4f8c6af..6409392 100644
--- a/src/pages/Documents/DocumentsTemplate.jsx
+++ b/src/pages/Documents/DocumentsTemplate.jsx
@@ -8,7 +8,7 @@ import {
formatBytes,
} from "../../components/factory"
import { EditableTable, makePaginationObject } from "../../components/Table"
-import UploadForm from "../../components/UploadForm"
+import {UploadForm} from "../../components/UploadForm"
import LoaderPortal from "../../components/LoaderPortal"
import {UserView} from '../../components/UserView'
import {CompanyView} from '../../components/CompanyView'
diff --git a/src/pages/Measure/MeasureTable.jsx b/src/pages/Measure/MeasureTable.jsx
index 7aab0f0..4831ec6 100644
--- a/src/pages/Measure/MeasureTable.jsx
+++ b/src/pages/Measure/MeasureTable.jsx
@@ -1,54 +1,198 @@
import { useState, useEffect } from 'react'
-import { Table, Button, Modal } from 'antd'
-import { HourglassOutlined } from '@ant-design/icons'
+import { Button, Form, Input, Popconfirm, Timeline } from 'antd'
+import moment from 'moment'
+import { CheckSquareOutlined,
+ EditOutlined,
+ SaveOutlined,
+ PlusOutlined,
+ CloseCircleOutlined,
+ DeleteOutlined } from '@ant-design/icons'
+import { View } from './View'
import LoaderPortal from '../../components/LoaderPortal'
-import { invokeWebApiWrapperAsync } from '../../components/factory'
import { MeasureService } from '../../services/api'
-import { Editor } from './Editor'
+import '../../styles/index.css'
+import '../../styles/measure.css'
-export const MeasureTable = ({idWell, idCategory, title, columns}) => {
- const [showLoader, setShowLoader] = useState(false)
- const [showEditor, setShowEditor] = useState(false)
- const [lastData, setLastData] = useState({})
+const format='YYYY.MM.DD HH:mm'
- const update = ()=>invokeWebApiWrapperAsync(async()=>{
- const data = await MeasureService.getLast(idWell, idCategory)
- setLastData(data)
+export const MeasureTable = ({idWell, idCategory, title, columns, values, updateMeasuresFunc}) => {
+
+ const [showLoader, setShowLoader] = useState(false);
+ const [displayedValues, setDisplayedValues] = useState({});
+ const [editingColumns, setEditingColumns] = useState(columns);
+ const [isTableEditing, setIsTableEditing] = useState(false);
+ const [editingActionName, setEditingActionName] = useState('');
+
+ const [measuresForm] = Form.useForm();
+
+ const createEditingColumns = (cols, renderDelegate) =>
+ cols.map(col =>
+ ({ render: renderDelegate,
+ ...col
+ })
+ )
+
+ useEffect(() => {
+ const defaultValuesToDisplay = values[values.length-1]
+
+ setDisplayedValues(defaultValuesToDisplay)
+ }, [values])
+
+ useEffect(() => {
+ let switchableColumns = []
+
+ isTableEditing
+ ? switchableColumns = createEditingColumns(columns, () => )
+ : switchableColumns = createEditingColumns(columns, null)
+
+ if(editingActionName === 'edit')
+ measuresForm.setFieldsValue(displayedValues?.data);
+ else if(editingActionName === 'add')
+ measuresForm.resetFields()
+
+ setEditingColumns(switchableColumns)
+ }, [isTableEditing, columns, editingActionName, displayedValues?.data, measuresForm])
+
+ const markMeasuresAsDeleted = async () => {
+ setShowLoader(true)
+ await MeasureService.markAsDelete(idWell, displayedValues.id)
+ updateMeasuresFunc()
+ setShowLoader(false)
}
- , setShowLoader
- , "не удалось загрузить")
- useEffect(update, [idWell, idCategory])
+ const checkIsDataDefault = () =>
+ displayedValues?.isDefaultData ? true : false
- const timestamp = lastData ? new Date(lastData?.timestamp).toLocaleString() : '-'
-
- return
- {title}
- Дата: {timestamp}
-
-
-
- setShowEditor(false)}
- onCancel={() => setShowEditor(false)}
- width="95%"
- footer={null}
+ const crudButtons =
+
+
+
+
markMeasuresAsDeleted()}
+ disabled={checkIsDataDefault()}
+ >
+
+
+
+
+ const confirmButtons =
+
+
+
+
+
+
+
+ let handleSubmitMeasuresForm = async (formData) => {
+ measuresForm.validateFields()
+
+ const measureParams = {
+ idWell: idWell,
+ idCategory: idCategory,
+ timestamp: new Date().toISOString(),
+ data: formData
+ }
+
+ setShowLoader(true)
+
+ if(editingActionName === 'add') {
+ await MeasureService.insert(idWell, measureParams)
+ } else if (editingActionName === 'edit') {
+ measureParams.id = displayedValues.id
+ measureParams.timestamp = displayedValues.timestamp
+ await MeasureService.update(idWell, measureParams)
+ }
+
+ setIsTableEditing(false)
+ updateMeasuresFunc()
+ setShowLoader(false)
+ }
+
+ return <>
+
+ {title}
+
+
+
+
+ {isTableEditing
+ ? confirmButtons
+ : crudButtons
+ }
+
+
+
+
+ {values.map((item, index) =>
+ setDisplayedValues(item)}
+ dot={item?.id === displayedValues?.id
+ ?
+ : null}
+ >
+
+ {item.timestamp ? moment.utc(item.timestamp).local().format(format) : 'Нет данных'}
+
+
+ )}
+
+
+
+
+
+
+
+
+
+ >
}
\ No newline at end of file
diff --git a/src/pages/Measure/MeasureTable2.jsx b/src/pages/Measure/MeasureTableOld.jsx
similarity index 53%
rename from src/pages/Measure/MeasureTable2.jsx
rename to src/pages/Measure/MeasureTableOld.jsx
index 621e711..7aab0f0 100644
--- a/src/pages/Measure/MeasureTable2.jsx
+++ b/src/pages/Measure/MeasureTableOld.jsx
@@ -1,48 +1,40 @@
import { useState, useEffect } from 'react'
-import { Button, Modal, Timeline } from 'antd'
-import moment from 'moment'
+import { Table, Button, Modal } from 'antd'
import { HourglassOutlined } from '@ant-design/icons'
import LoaderPortal from '../../components/LoaderPortal'
import { invokeWebApiWrapperAsync } from '../../components/factory'
import { MeasureService } from '../../services/api'
import { Editor } from './Editor'
-import TimelineItem from 'antd/lib/timeline/TimelineItem'
-//import { View } from './View'
-const format='YYYY.MM.DD HH:mm'
-
-export const MeasureTable2 = ({idWell, idCategory, title, columns}) => {
+export const MeasureTable = ({idWell, idCategory, title, columns}) => {
const [showLoader, setShowLoader] = useState(false)
const [showEditor, setShowEditor] = useState(false)
- const [history, setHistory] = useState([])
+ const [lastData, setLastData] = useState({})
- const update = () => invokeWebApiWrapperAsync(async()=>{
- const data = await MeasureService.getHisory(idWell, idCategory)
- const story = data?.map( i=> ({
- id: i.id,
- idWell: i.idWell,
- idCategory: i.idCategory,
- timestamp: moment.utc(i.timestamp).local().format(format),
- ...i.data}))
- setHistory(story??[])
+ const update = ()=>invokeWebApiWrapperAsync(async()=>{
+ const data = await MeasureService.getLast(idWell, idCategory)
+ setLastData(data)
}
, setShowLoader
, "не удалось загрузить")
useEffect(update, [idWell, idCategory])
+ const timestamp = lastData ? new Date(lastData?.timestamp).toLocaleString() : '-'
+
return
{title}
+ Дата: {timestamp}
-
- {history.map(item=>{item.timestamp})}
-
- {/* */}
+ icon={}>История
+
{
+ if(column.render) {
+ return (
+
+ {column.render(itm[column.dataIndex])}
+
+ )
+ }
+
+ return {itm[column.dataIndex]}
+}
export const View = ({columns, item}) => {
if (!item || !columns?.length)
- return
+ return
const colsCount = 3
const viewItems = columns.map( (column, i) => {
const row = Math.floor(i / colsCount) + 1
const colb = i % colsCount
+
return <>
+ style={{border:'1px solid lightgrey'}}
+ >
{column.title}
-
+
- {column.render ? column.render(item[column.dataIndex]) : item[column.dataIndex]}
+ style={{border:'1px solid lightgrey',
+ justifyContent:'right',
+ marginRight:'16px',
+ fontWeight:'bold',
+ textAlign:'right',
+ padding: 0}}
+ >
+ {renderSwitchableColumn(column, item)}
>
})
- return
- {viewItems}
-
+ return <>
+
+ {viewItems}
+
+ >
}
\ No newline at end of file
diff --git a/src/pages/Measure/columnsCommon.js b/src/pages/Measure/columnsCommon.js
index 7d458b5..5e7a616 100644
--- a/src/pages/Measure/columnsCommon.js
+++ b/src/pages/Measure/columnsCommon.js
@@ -42,4 +42,10 @@ export const numericColumnOptions = {
export const textColumnOptions = {
editable:true,
input:,
- width:'20rem'}
\ No newline at end of file
+ width:'20rem',
+ formItemRules: [
+ {
+ required: true,
+ message: `Введите текст`
+ },
+ ],}
\ No newline at end of file
diff --git a/src/pages/Measure/columnsMudDiagram.js b/src/pages/Measure/columnsMudDiagram.js
deleted file mode 100644
index 5a82670..0000000
--- a/src/pages/Measure/columnsMudDiagram.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import {makeColumn} from '../../components/Table'
-import {v, numericColumnOptions, textColumnOptions} from './columnsCommon'
-
-export const columnsMudDiagram = [
- makeColumn(v('N пробы'), 'probeNumber', numericColumnOptions),
- makeColumn(v('Глубина отбора пробы'), 'probeExtractionDepth', numericColumnOptions),
- {
- title: 'Литология',
- key: 'lithology',
- children: [
- makeColumn(v('Песчаник (%)'), 'sandstone', numericColumnOptions),
- makeColumn(v('Алевролит (%)'), 'siltstone', numericColumnOptions),
- makeColumn(v('Аргиллит (%)'), 'argillit', numericColumnOptions),
- makeColumn(v('Аргиллит бит. (%)'), 'brokenArgillit', numericColumnOptions),
- makeColumn(v('Уголь (%)'), 'coal', numericColumnOptions),
- makeColumn(v('Песок (%)'), 'sand', numericColumnOptions),
- makeColumn(v('Глина (%)'), 'clay', numericColumnOptions),
- makeColumn(v('Известняк (%)'), 'camstone', numericColumnOptions),
- makeColumn(v('Цемент (%)'), 'cement', numericColumnOptions),
- ]
- },
- makeColumn('Краткое описание', 'summary', textColumnOptions),
- makeColumn(v('ЛБА бурового раствора'), 'drillingMud', numericColumnOptions),
- makeColumn(v('ЛБА (шлама)'), 'sludge', numericColumnOptions),
- {
- title: 'Газопоказания',
- key: 'gasIndications',
- children: [
- makeColumn(v('Сумма УВ мах. (абс%)'), 'maxSum', numericColumnOptions),
- makeColumn(v('С1 метан (отн%)'), 'methane', numericColumnOptions),
- makeColumn(v('С2 этан (отн%)'), 'ethane', numericColumnOptions),
- makeColumn(v('С3 пропан (отн%)'), 'propane', numericColumnOptions),
- makeColumn(v('С4 бутан (отн%)'), 'butane', numericColumnOptions),
- makeColumn(v('С5 пентан (отн%)'), 'pentane', numericColumnOptions),
- ]
- },
- makeColumn(v('Мех. скорость'), 'mechanicalSpeed', numericColumnOptions),
- makeColumn('Предварительное заключение о насыщении по ГК', 'preliminaryConclusion', textColumnOptions),
-]
\ No newline at end of file
diff --git a/src/pages/Measure/columnsDrillingFluid.js b/src/pages/Measure/drillingFluidData.js
similarity index 76%
rename from src/pages/Measure/columnsDrillingFluid.js
rename to src/pages/Measure/drillingFluidData.js
index 41dc820..0783106 100644
--- a/src/pages/Measure/columnsDrillingFluid.js
+++ b/src/pages/Measure/drillingFluidData.js
@@ -31,3 +31,40 @@ export const columnsDrillingFluid = [
makeColumn(v("Смазка, %"), "grease",numericColumnOptions),
makeColumn(v("Карбонат кальция, кг/м³"), "calciumCarbonate",numericColumnOptions),
];
+
+export const drillingFluidDefaultData = {
+ idWell: 0,
+ key: 'drillingFluidDefaultData',
+ idCategory: 0,
+ isDefaultData: true,
+ data: {
+ "name": 0,
+ "temperature": 0,
+ "density": 0,
+ "conditionalViscosity": 0,
+ "r300": 0,
+ "r600": 0,
+ "r3r6": 0,
+ "dnsDpa": 0,
+ "plasticViscocity": 0,
+ "snsDpa": 0,
+ "r3r649С": 0,
+ "dns49Cdpa": 0,
+ "plasticViscocity49c": 0,
+ "sns49Cdpa": 0,
+ "mbt": 0,
+ "sand": 0,
+ "filtering": 0,
+ "crust": 0,
+ "ktk": 0,
+ "ph": 0,
+ "hardness": 0,
+ "chlorides": 0,
+ "pf": 0,
+ "mf": 0,
+ "pm": 0,
+ "fluidSolidPhase": 0,
+ "grease": 0,
+ "calciumCarbonate": 0
+ }
+}
diff --git a/src/pages/Measure/index.jsx b/src/pages/Measure/index.jsx
index 105926c..e4b6dd9 100644
--- a/src/pages/Measure/index.jsx
+++ b/src/pages/Measure/index.jsx
@@ -1,25 +1,64 @@
-import { columnsMudDiagram} from './columnsMudDiagram'
-import { columnsDrillingFluid} from './columnsDrillingFluid'
-import { columnsNnb } from './columnsNnb'
+import { useState, useEffect } from 'react'
+import { columnsMudDiagram} from './mudDiagramData'
+import { mudDiagramDefaultData} from './mudDiagramData'
+import { columnsDrillingFluid} from './drillingFluidData'
+import { drillingFluidDefaultData} from './drillingFluidData'
+import { columnsNnb } from './nnbData'
+import { nnbDefaultData } from './nnbData'
+import { invokeWebApiWrapperAsync } from '../../components/factory'
+import { MeasureService } from '../../services/api'
+import LoaderPortal from '../../components/LoaderPortal'
import { MeasureTable } from './MeasureTable'
-//import { MeasureTable2 } from './MeasureTable2'
export default function Measure({idWell}){
+ const [showLoader, setShowLoader] = useState(false)
+ const [fluidValues, setFluidValues] = useState([])
+ const [mudValues, setMudValues] = useState([])
+ const [nnbValues, setNnbValues] = useState([])
+ const [isMeasuresUpdating, setIsMeasuresUpdating] = useState(false)
+
+ const updateCurrentValues = () => invokeWebApiWrapperAsync(async()=>{
+ const measures = await MeasureService.getHisory(idWell)
+ setIsMeasuresUpdating(false)
+
+ const fluids = measures.filter(el => el.idCategory === 1)
+ setFluidValues(fluids.length ? fluids : [drillingFluidDefaultData])
+ const muds = measures.filter(el => el.idCategory === 2)
+ setMudValues(muds.length ? muds : [mudDiagramDefaultData])
+ const nnbs = measures.filter(el => el.idCategory === 3)
+ setNnbValues(nnbs.length ? nnbs : [nnbDefaultData])
+ }
+ ,setShowLoader
+ ,`Не удалось загрузить последние данные по скважине ${idWell}`)
+
+ useEffect(updateCurrentValues, [idWell, isMeasuresUpdating])
+
return <>
-
-
-
+
+ setIsMeasuresUpdating(true)}
+ />
+ setIsMeasuresUpdating(true)}
+ />
+ setIsMeasuresUpdating(true)}
+ />
+
>
}
\ No newline at end of file
diff --git a/src/pages/Measure/mudDiagramData.js b/src/pages/Measure/mudDiagramData.js
new file mode 100644
index 0000000..89256a5
--- /dev/null
+++ b/src/pages/Measure/mudDiagramData.js
@@ -0,0 +1,58 @@
+import {makeColumn} from '../../components/Table'
+import {v, numericColumnOptions, textColumnOptions} from './columnsCommon'
+
+export const columnsMudDiagram = [
+ makeColumn(v('N пробы'), 'probeNumber', numericColumnOptions),
+ makeColumn(v('Глубина отбора пробы'), 'probeExtractionDepth', numericColumnOptions),
+ makeColumn(v('Песчаник (%)'), 'sandstone', numericColumnOptions),
+ makeColumn(v('Алевролит (%)'), 'siltstone', numericColumnOptions),
+ makeColumn(v('Аргиллит (%)'), 'argillit', numericColumnOptions),
+ makeColumn(v('Аргиллит бит. (%)'), 'brokenArgillit', numericColumnOptions),
+ makeColumn(v('Уголь (%)'), 'coal', numericColumnOptions),
+ makeColumn(v('Песок (%)'), 'sand', numericColumnOptions),
+ makeColumn(v('Глина (%)'), 'clay', numericColumnOptions),
+ makeColumn(v('Известняк (%)'), 'camstone', numericColumnOptions),
+ makeColumn(v('Цемент (%)'), 'cement', numericColumnOptions),
+ makeColumn('Краткое описание', 'summary', textColumnOptions),
+ makeColumn(v('ЛБА бурового раствора'), 'drillingMud', numericColumnOptions),
+ makeColumn(v('ЛБА (шлама)'), 'sludge', numericColumnOptions),
+ makeColumn(v('Сумма УВ мах. (абс%)'), 'maxSum', numericColumnOptions),
+ makeColumn(v('С1 метан (отн%)'), 'methane', numericColumnOptions),
+ makeColumn(v('С2 этан (отн%)'), 'ethane', numericColumnOptions),
+ makeColumn(v('С3 пропан (отн%)'), 'propane', numericColumnOptions),
+ makeColumn(v('С4 бутан (отн%)'), 'butane', numericColumnOptions),
+ makeColumn(v('С5 пентан (отн%)'), 'pentane', numericColumnOptions),
+ makeColumn(v('Мех. скорость'), 'mechanicalSpeed', numericColumnOptions),
+ makeColumn('Предварительное заключение о насыщении по ГК', 'preliminaryConclusion', textColumnOptions),
+]
+
+export const mudDiagramDefaultData = {
+ idWell: 0,
+ key: 'mudDiagramDefaultData',
+ idCategory: 0,
+ isDefaultData: true,
+ data: {
+ "probeNumber": 0,
+ "probeExtractionDepth": 0,
+ "sandstone": 0,
+ "siltstone": 0,
+ "argillit": 0,
+ "brokenArgillit": 0,
+ "coal": 0,
+ "sand": 0,
+ "clay": 0,
+ "camstone": 0,
+ "cement": 0,
+ "summary": '-',
+ "drillingMud": 0,
+ "sludge": 0,
+ "maxSum": 0,
+ "methane": 0,
+ "ethane": 0,
+ "propane": 0,
+ "butane": 0,
+ "pentane": 0,
+ "mechanicalSpeed": 0,
+ "preliminaryConclusion": '-'
+ }
+}
\ No newline at end of file
diff --git a/src/pages/Measure/columnsNnb.js b/src/pages/Measure/nnbData.js
similarity index 78%
rename from src/pages/Measure/columnsNnb.js
rename to src/pages/Measure/nnbData.js
index f309328..2f7e770 100644
--- a/src/pages/Measure/columnsNnb.js
+++ b/src/pages/Measure/nnbData.js
@@ -19,4 +19,30 @@ export const columnsNnb = [
makeColumn(v('Комментарий'), 'comment', numericColumnOptions),
makeColumn(v('Разница вертикальных глубин\nмежду планом и фактом'), 'depthPlanFactDifference', numericColumnOptions),
makeColumn(v('Расстояние в пространстве\nмежду планом и фактом'), 'distancePlanFactDifference', numericColumnOptions),
-];
\ No newline at end of file
+];
+
+export const nnbDefaultData = {
+ idWell: 0,
+ key: 'nnbDefaultData',
+ idCategory: 0,
+ isDefaultData: true,
+ data: {
+ "depth": 0,
+ "zenithAngle": 0,
+ "magneticAzimuth": 0,
+ "trueAzimuth": 0,
+ "directAzimuth": 0,
+ "verticalDepth": 0,
+ "absoluteMark": 0,
+ "localNorthOffset": 0,
+ "localEastOffset": 0,
+ "outFallOffset": 0,
+ "offsetAzimuth": 0,
+ "areaIntensity": '-',
+ "offsetStopAngle": 0,
+ "zenithIntensity": 0,
+ "comment": '-',
+ "depthPlanFactDifference": 0,
+ "distancePlanFactDifference": 0
+ }
+}
\ No newline at end of file
diff --git a/src/pages/Report/Reports.jsx b/src/pages/Report/Reports.jsx
index 064be92..322171e 100644
--- a/src/pages/Report/Reports.jsx
+++ b/src/pages/Report/Reports.jsx
@@ -1,5 +1,5 @@
import { useState, useEffect } from "react"
-import { Table, makeDateSorter, makeNumericSorter, formatDate} from "../../components/Table"
+import { Table, formatDate, makeDateSorter, makeNumericSorter} from "../../components/Table"
import { Button, Tooltip } from "antd"
import { FilePdfOutlined, FileTextOutlined} from '@ant-design/icons'
import { ReportService } from "../../services/api"
diff --git a/src/pages/Well.jsx b/src/pages/Well.jsx
index 01103e5..9da4b48 100644
--- a/src/pages/Well.jsx
+++ b/src/pages/Well.jsx
@@ -46,7 +46,7 @@ export default function Well() {
Рапорт
}>
- Операции по скважине
+ Операции по скважине
}>
Архив
@@ -89,7 +89,7 @@ export default function Well() {
-
+
diff --git a/src/components/charts/ChartDepthToDay.jsx b/src/pages/WellOperations/ChartTvD.jsx
similarity index 92%
rename from src/components/charts/ChartDepthToDay.jsx
rename to src/pages/WellOperations/ChartTvD.jsx
index dcd7cde..499484f 100644
--- a/src/components/charts/ChartDepthToDay.jsx
+++ b/src/pages/WellOperations/ChartTvD.jsx
@@ -97,7 +97,7 @@ const makeDataset = (data, label, color, width=1.5, dash) => ({
borderDash: dash,
})
-export default function ChartDepthToDay({dataPlan, dataFact, dataForecast}) {
+export default function ChartTvD({dataPlan, dataFact, dataPredict}) {
const chartRef = useRef(null)
const [chart, setChart] = useState()
@@ -105,7 +105,7 @@ export default function ChartDepthToDay({dataPlan, dataFact, dataForecast}) {
let data = {
datasets: [
makeDataset(dataFact, 'Факт', '#0A0'),
- makeDataset(dataForecast, 'Прогноз', 'purple', 1, [7,3]),
+ makeDataset(dataPredict, 'Прогноз', 'purple', 1, [7,3]),
makeDataset(dataPlan, 'План', '#C004', 4),
]
}
@@ -127,7 +127,7 @@ export default function ChartDepthToDay({dataPlan, dataFact, dataForecast}) {
chart.data = data
chart.update()
}
- }, [chart, dataPlan, dataFact, dataForecast])
+ }, [chart, dataPlan, dataFact, dataPredict])
return ()
}
\ No newline at end of file
diff --git a/src/pages/WellOperations/ImportExportBar.jsx b/src/pages/WellOperations/ImportExportBar.jsx
new file mode 100644
index 0000000..11addca
--- /dev/null
+++ b/src/pages/WellOperations/ImportExportBar.jsx
@@ -0,0 +1,54 @@
+import { Button, Tooltip, Modal } from "antd";
+import {useState} from 'react'
+import { FileOutlined, ImportOutlined, ExportOutlined } from '@ant-design/icons'
+import { download } from '../../components/factory'
+import { ImportOperations } from './ImportOperations'
+
+const style = {margin:4}
+
+export const ImportExportBar = ({idWell, onImported}) =>{
+ const [isImportModalVisible, setIsImportModalVisible] = useState(false)
+
+ const downloadTemplate = async () => download(`/api/well/${idWell}/wellOperations/tamplate`)
+ const downloadExport = async () => download(`/api/well/${idWell}/wellOperations/export`)
+
+ const onDone = () => {
+ setIsImportModalVisible(false)
+ if(onImported)
+ onImported()
+ }
+
+ return <>
+
+
+
+
+
+
+
+
+
+ setIsImportModalVisible(false)}
+
+ footer={null}>
+
+
+ >
+}
\ No newline at end of file
diff --git a/src/pages/WellOperations/ImportOperations.jsx b/src/pages/WellOperations/ImportOperations.jsx
new file mode 100644
index 0000000..22c43f1
--- /dev/null
+++ b/src/pages/WellOperations/ImportOperations.jsx
@@ -0,0 +1,41 @@
+import {Switch} from 'antd'
+import {useState} from 'react'
+import { ErrorFetch } from '../../components/ErrorFetch'
+import {UploadForm} from '../../components/UploadForm'
+
+export const ImportOperations = ({idWell, onDone}) =>{
+ const [deleteBeforeImport, setDeleteBeforeImport] = useState(false)
+ const [errorText, setErrorText] = useState('')
+
+ const url = `/api/well/${idWell}/wellOperations/import`
+
+ const onUploadSuccess = () => {
+ setErrorText('')
+ if(onDone)
+ onDone()
+ }
+
+ const onUploadError = (error) => {
+ if(error instanceof ErrorFetch && error.status === 400)
+ setErrorText(`Не удалось импортировать.\n ${error?.message}`)
+ else
+ setErrorText(`Не удалось импортировать.`)
+ }
+
+ const getUrl = () => deleteBeforeImport
+ ? url + '/1'
+ : url + '/0'
+
+ return
+
Загрузить файл excel с операциями на сервер
+
Очистить список операций перед импортом
+
+
+ {errorText}
+
+}
\ No newline at end of file
diff --git a/src/pages/WellOperations/Tvd.jsx b/src/pages/WellOperations/Tvd.jsx
index 14b574d..97922d2 100644
--- a/src/pages/WellOperations/Tvd.jsx
+++ b/src/pages/WellOperations/Tvd.jsx
@@ -1,4 +1,4 @@
-import ChartDepthToDay from '../../components/charts/ChartDepthToDay';
+import ChartTvD from './ChartTvD';
import { useState, useEffect } from 'react';
import { invokeWebApiWrapperAsync } from '../../components/factory';
import { getOperations } from '../Cluster/functions';
@@ -7,18 +7,15 @@ import { getOperations } from '../Cluster/functions';
export const Tvd = ({ idWell }) => {
const [dataPlan, setDataPlan] = useState([]);
const [dataFact, setDataFact] = useState([]);
- const [dataForecast, setDataForecast] = useState([]);
+ const [dataPredict, setDataPredict] = useState([]);
useEffect(() => {
invokeWebApiWrapperAsync(
async () => {
const operations = await getOperations(idWell);
-
setDataPlan(operations.plan)
-
setDataFact(operations.fact)
-
- setDataForecast(operations.predict)
+ setDataPredict(operations.predict)
},
null,
`Не удалось загрузить операции по скважине "${idWell}"`,
@@ -29,10 +26,10 @@ export const Tvd = ({ idWell }) => {
График Глубина-день
-
+ dataPredict={dataPredict} />
);
diff --git a/src/pages/WellOperations/WellOperationsEditor.jsx b/src/pages/WellOperations/WellOperationsEditor.jsx
index 8bacc16..1f07d86 100644
--- a/src/pages/WellOperations/WellOperationsEditor.jsx
+++ b/src/pages/WellOperations/WellOperationsEditor.jsx
@@ -6,10 +6,8 @@ import {
DatePickerWrapper,
SelectFromDictionary,
makeColumn,
- numericColumnOptions,
- makeNumericSorter,
makeDateSorter,
- defaultNumericRender } from "../../components/Table"
+ makeNumericColumnOptions} from "../../components/Table"
import LoaderPortal from '../../components/LoaderPortal'
import { invokeWebApiWrapperAsync } from '../../components/factory'
import { WellOperationService} from '../../services/api'
@@ -20,20 +18,6 @@ const { TextArea } = Input;
const basePageSize = 160;
const format='YYYY.MM.DD HH:mm'
-const numericSortColumnOptions = {
- ...numericColumnOptions,
- sorter: makeNumericSorter('wellDepth'),
- render:(value) =>
-
- {value}
-
-}
-
-const durationFormattedColumnOptions = {
- ...numericColumnOptions,
- render: defaultNumericRender
-}
-
export const WellOperationsEditor = ({idWell, idType}) => {
const [pageNumAndPageSize, setPageNumAndPageSize] = useState({current:1, pageSize:basePageSize})
const [paginationTotal, setPaginationTotal] = useState(0)
@@ -81,19 +65,20 @@ export const WellOperationsEditor = ({idWell, idType}) => {
render:(_, record)=>getByKeyOrReturnKey(dictionaryOperationCategory, record.idCategory)
}),
makeColumn('Доп. инфо','categoryInfo', {editable:true, width:300, input:}),
- makeColumn('Глубина забоя','wellDepth', numericSortColumnOptions),
- makeColumn('Время начала','startDate', {
+ makeColumn('Глубина забоя на начало','depthStart', makeNumericColumnOptions(2, 'depthStart')),
+ makeColumn('Глубина забоя при завершении','depthEnd', makeNumericColumnOptions(2, 'depthEnd')),
+ makeColumn('Время начала','dateStart', {
editable:true,
width:200,
input:,
initialValue:moment().format(),
- sorter: makeDateSorter('startDate'),
+ sorter: makeDateSorter('dateStart'),
render:(_, record) =>
- {moment.utc(record.startDate).local().format(format)}
+ {moment.utc(record.dateStart).local().format(format)}
}),
- makeColumn('Часы','durationHours', durationFormattedColumnOptions),
+ makeColumn('Часы','durationHours', makeNumericColumnOptions(2, 'durationHours')),
makeColumn('Комментарий','comment', {editable:true, input:}),
]
diff --git a/src/pages/WellOperations/index.jsx b/src/pages/WellOperations/index.jsx
index e3f5ac3..d23b2dc 100644
--- a/src/pages/WellOperations/index.jsx
+++ b/src/pages/WellOperations/index.jsx
@@ -1,17 +1,22 @@
import {Layout, Menu} from "antd";
-import {Switch, Link, Route, Redirect, useParams} from "react-router-dom";
+import {Switch, Link, Route, Redirect, useParams, useHistory} from "react-router-dom";
import { FolderOutlined } from "@ant-design/icons";
import { WellOperationsEditor } from './WellOperationsEditor'
import { WellSectionsStat } from './WellSectionsStat'
import { Tvd } from './Tvd'
-import { WellOpeationsModes } from './WellOpeationsModes'
+import { ImportExportBar } from "./ImportExportBar";
const { Content } = Layout
export default function WellOperations({idWell}) {
let {tab} = useParams()
+ let history = useHistory()
const rootPath = `/well/${idWell}/operations`;
+ const onImported = () => {
+ history.push(`${rootPath}`)
+ }
+
return(<>
}>
Режимы
+
@@ -53,7 +59,7 @@ export default function WellOperations({idWell}) {
-
+
diff --git a/src/services/api/models/DrillParamsDto.ts b/src/services/api/models/DrillParamsDto.ts
index 24d5751..8f5289b 100644
--- a/src/services/api/models/DrillParamsDto.ts
+++ b/src/services/api/models/DrillParamsDto.ts
@@ -20,7 +20,7 @@ export type DrillParamsDto = {
topDriveSpeedMin?: number;
topDriveSpeedAvg?: number;
topDriveSpeedMax?: number;
- flowMin?: number;
- flowAvg?: number;
- flowMax?: number;
+ consumptionMin?: number;
+ consumptionAvg?: number;
+ consumptionMax?: number;
}
diff --git a/src/services/api/services/AdminTelemetryService.ts b/src/services/api/services/AdminTelemetryService.ts
index ce158b8..17a7e23 100644
--- a/src/services/api/services/AdminTelemetryService.ts
+++ b/src/services/api/services/AdminTelemetryService.ts
@@ -25,8 +25,8 @@ export class AdminTelemetryService {
* @throws ApiError
*/
public static async mergeTelemetries(
- requestBody?: Array,
- ): Promise {
+requestBody?: Array,
+): Promise {
const result = await __request({
method: 'POST',
path: `/merge`,
diff --git a/src/services/api/services/DrillParamsService.ts b/src/services/api/services/DrillParamsService.ts
index 4c5266d..70247da 100644
--- a/src/services/api/services/DrillParamsService.ts
+++ b/src/services/api/services/DrillParamsService.ts
@@ -15,10 +15,10 @@ export class DrillParamsService {
* @throws ApiError
*/
public static async getDefaultDrillParams(
- idWell?: number,
- startDepth?: number,
- endDepth?: number,
- ): Promise {
+idWell?: number,
+startDepth?: number,
+endDepth?: number,
+): Promise {
const result = await __request({
method: 'GET',
path: `/drillParams/idWell/autoParams`,
@@ -39,9 +39,9 @@ export class DrillParamsService {
* @throws ApiError
*/
public static async saveDrillParams(
- idWell?: number,
- requestBody?: DrillParamsDto,
- ): Promise {
+idWell?: number,
+requestBody?: DrillParamsDto,
+): Promise {
const result = await __request({
method: 'POST',
path: `/drillParams/idWell`,
diff --git a/src/services/api/services/WellOperationService.ts b/src/services/api/services/WellOperationService.ts
index ca2cfa2..1f8261b 100644
--- a/src/services/api/services/WellOperationService.ts
+++ b/src/services/api/services/WellOperationService.ts
@@ -149,15 +149,15 @@ export class WellOperationService {
* Импортирует операции из excel (xlsx) файла
* @param idWell id скважины
* @param options Удалить операции перед импортом = 1, если фал валидный
- * @param requestBody
+ * @param requestBody
* @returns any Success
* @throws ApiError
*/
public static async import(
- idWell: number,
- options: number,
- requestBody?: any,
- ): Promise {
+idWell: number,
+options: number,
+requestBody?: any,
+): Promise {
const result = await __request({
method: 'POST',
path: `/api/well/${idWell}/wellOperations/import/${options}`,
@@ -173,8 +173,8 @@ export class WellOperationService {
* @throws ApiError
*/
public static async export(
- idWell: number,
- ): Promise {
+idWell: number,
+): Promise {
const result = await __request({
method: 'GET',
path: `/api/well/${idWell}/wellOperations/export`,
@@ -184,13 +184,13 @@ export class WellOperationService {
/**
* Возвращает шаблон файла импорта
- * @param idWell
+ * @param idWell
* @returns string Success
* @throws ApiError
*/
public static async getTamplate(
- idWell: string,
- ): Promise {
+idWell: string,
+): Promise {
const result = await __request({
method: 'GET',
path: `/api/well/${idWell}/wellOperations/tamplate`,
diff --git a/src/styles/index.css b/src/styles/index.css
index ae77b2e..59c2d76 100644
--- a/src/styles/index.css
+++ b/src/styles/index.css
@@ -11,6 +11,10 @@ body {
display: flex;
}
+.flex-direction-column {
+ flex-direction: column;
+}
+
.d-inline {
display: inline;
}
@@ -19,10 +23,30 @@ body {
display: none;
}
+.w-15 {
+ width: 15%
+}
+
+.w-33 {
+ width: 33%
+}
+
+.w-50 {
+ width: 50%
+}
+
.w-100 {
width: 100%
}
+.m-0 {
+ margin: 0;
+}
+
+.mt-8px {
+ margin-top: 8px;
+}
+
.mt-20px {
margin-top: 20px;
}
@@ -35,6 +59,10 @@ body {
margin-left: 5px;
}
+.ml-10px {
+ margin-left: 10px;
+}
+
.ml-30px {
margin-left: 30px;
}
diff --git a/src/styles/measure.css b/src/styles/measure.css
new file mode 100644
index 0000000..1425fdc
--- /dev/null
+++ b/src/styles/measure.css
@@ -0,0 +1,36 @@
+input.measure-input {
+ font-weight:bold;
+}
+
+.w-300px {
+ width: 300px;
+}
+
+.measure-buttons-container {
+ height: 30px;
+}
+
+.measure-dates {
+ height: 160px;
+ overflow-y: scroll;
+}
+
+.measure-button:hover {
+ cursor: pointer;
+}
+
+.selected-timeline {
+ font-weight: bold;
+}
+
+.m-5px {
+ margin: 5px 5px;
+}
+
+.mt-12px {
+ margin-top: 12px;
+}
+
+.ml-10px {
+ margin-left: 10px;
+}