Compare commits

...

2 Commits

Author SHA1 Message Date
Александр Васильевич Сироткин
b4ae4efa43 Merged dev into feature/DrillProcessFlow 2022-09-04 19:34:18 +00:00
a.chernyshev
a7bd5d961f edit drillProcessFlow page 2022-08-28 15:57:58 +05:00
8 changed files with 455 additions and 49 deletions

36
package-lock.json generated
View File

@ -54,7 +54,7 @@
"url-loader": "^4.1.1",
"webpack": "^5.73.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.9.1"
"webpack-dev-server": "^4.10.0"
}
},
"node_modules/@ampproject/remapping": {
@ -4741,9 +4741,9 @@
"dev": true
},
"node_modules/connect-history-api-fallback": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz",
"integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz",
"integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==",
"dev": true,
"engines": {
"node": ">=0.8"
@ -11743,15 +11743,16 @@
}
},
"node_modules/webpack-dev-server": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.9.1.tgz",
"integrity": "sha512-CTMfu2UMdR/4OOZVHRpdy84pNopOuigVIsRbGX3LVDMWNP8EUgC5mUBMErbwBlHTEX99ejZJpVqrir6EXAEajA==",
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.10.0.tgz",
"integrity": "sha512-7dezwAs+k6yXVFZ+MaL8VnE+APobiO3zvpp3rBHe/HmWQ+avwh0Q3d0xxacOiBybZZ3syTZw9HXzpa3YNbAZDQ==",
"dev": true,
"dependencies": {
"@types/bonjour": "^3.5.9",
"@types/connect-history-api-fallback": "^1.3.5",
"@types/express": "^4.17.13",
"@types/serve-index": "^1.9.1",
"@types/serve-static": "^1.13.10",
"@types/sockjs": "^0.3.33",
"@types/ws": "^8.5.1",
"ansi-html-community": "^0.0.8",
@ -11759,7 +11760,7 @@
"chokidar": "^3.5.3",
"colorette": "^2.0.10",
"compression": "^1.7.4",
"connect-history-api-fallback": "^1.6.0",
"connect-history-api-fallback": "^2.0.0",
"default-gateway": "^6.0.3",
"express": "^4.17.3",
"graceful-fs": "^4.2.6",
@ -11783,6 +11784,10 @@
"engines": {
"node": ">= 12.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"peerDependencies": {
"webpack": "^4.37.0 || ^5.0.0"
},
@ -15682,9 +15687,9 @@
"dev": true
},
"connect-history-api-fallback": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz",
"integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz",
"integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==",
"dev": true
},
"content-disposition": {
@ -20915,15 +20920,16 @@
}
},
"webpack-dev-server": {
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.9.1.tgz",
"integrity": "sha512-CTMfu2UMdR/4OOZVHRpdy84pNopOuigVIsRbGX3LVDMWNP8EUgC5mUBMErbwBlHTEX99ejZJpVqrir6EXAEajA==",
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.10.0.tgz",
"integrity": "sha512-7dezwAs+k6yXVFZ+MaL8VnE+APobiO3zvpp3rBHe/HmWQ+avwh0Q3d0xxacOiBybZZ3syTZw9HXzpa3YNbAZDQ==",
"dev": true,
"requires": {
"@types/bonjour": "^3.5.9",
"@types/connect-history-api-fallback": "^1.3.5",
"@types/express": "^4.17.13",
"@types/serve-index": "^1.9.1",
"@types/serve-static": "^1.13.10",
"@types/sockjs": "^0.3.33",
"@types/ws": "^8.5.1",
"ansi-html-community": "^0.0.8",
@ -20931,7 +20937,7 @@
"chokidar": "^3.5.3",
"colorette": "^2.0.10",
"compression": "^1.7.4",
"connect-history-api-fallback": "^1.6.0",
"connect-history-api-fallback": "^2.0.0",
"default-gateway": "^6.0.3",
"express": "^4.17.3",
"graceful-fs": "^4.2.6",

View File

@ -19,12 +19,12 @@
"start": "webpack-dev-server --mode=development --open --hot",
"build": "webpack --mode=production",
"test": "jest",
"oul": "npx openapi -i http://127.0.0.1:5000/swagger/v1/swagger.json -o src/services/api",
"oul": "npx openapi -i http://localhost:52123/swagger/v1/swagger.json -o src/services/api",
"oud": "npx openapi -i http://192.168.1.70:5000/swagger/v1/swagger.json -o src/services/api",
"oug": "npx openapi -i http://46.146.209.148/swagger/v1/swagger.json -o src/services/api",
"oug_dev": "npx openapi -i http://46.146.209.148:89/swagger/v1/swagger.json -o src/services/api"
},
"proxy": "http://46.146.209.148:89",
"proxy": "http://localhost:52123",
"eslintConfig": {
"extends": [
"react-app",

View File

@ -12,12 +12,13 @@ export {
makeNumericColumnPlanFact,
makeNumericStartEnd,
makeNumericMinMax,
makeNumericDividedColumn,
makeNumericAvgRange
} from './numeric'
export { makeColumnsPlanFact } from './plan_fact'
export { makeSelectColumn } from './select'
export { makeTagColumn, makeTagInput } from './tag'
export { makeFilterTextMatch, makeTextColumn } from './text'
export { makeFilterTextMatch, makeTextColumn, makeDividedTextColumn } from './text'
export {
timezoneOptions,
TimezoneSelect,

View File

@ -56,6 +56,22 @@ export const makeNumericColumn = (
...other
})
export const makeNumericDividedColumn = (
title: ReactNode,
dataIndex: string,
filters: object[],
width: string,
other?: columnPropsOther
) => ({
title: title,
dataIndex: dataIndex,
key: dataIndex,
filters: filters,
width: width,
align: 'right',
...other
})
export const makeNumericColumnPlanFact = (
title: ReactNode,
dataIndex: string,

View File

@ -24,4 +24,17 @@ export const makeTextColumn = <T extends unknown = any>(
...other
})
export const makeDividedTextColumn = <T extends unknown = any>(
title: ReactNode,
dataIndex: string,
render?: RenderMethod<T>,
other?: columnPropsOther
) => ({
title: title,
dataIndex: dataIndex,
key: dataIndex,
render: render,
...other
})
export default makeTextColumn

View File

@ -16,6 +16,7 @@ export {
makeFilterTextMatch,
makeNumericRender,
makeNumericColumn,
makeNumericDividedColumn,
makeNumericColumnOptions,
makeNumericColumnPlanFact,
makeNumericStartEnd,
@ -25,6 +26,7 @@ export {
makeTagColumn,
makeTagInput,
makeTextColumn,
makeDividedTextColumn,
makeTimezoneColumn,
makeTimezoneRenderer,
} from './Columns'

View File

@ -1,29 +1,374 @@
import { useState, useEffect, memo, useMemo, useCallback } from 'react'
import React, { useState, useEffect, memo, useMemo, useCallback } from 'react'
import { InputNumber, Divider } from 'antd'
import { useWell } from '@asb/context'
import LoaderPortal from '@components/LoaderPortal'
import { invokeWebApiWrapperAsync } from '@components/factory'
import { EditableTable, makeNumericMinMax, makeNumericStartEnd } from '@components/Table'
import { DrillFlowChartService } from '@api'
import { EditableTable, makeNumericDividedColumn, makeNumericStartEnd, makeGroupColumn, makeSelectColumn, makeDividedTextColumn } from '@components/Table'
import { DrillFlowChartService, WellOperationService } from '@api'
import { arrayOrDefault } from '@utils'
const columns = [
makeNumericStartEnd('Глубина, м', 'depth'),
makeNumericMinMax('Нагрузка, т', 'axialLoad'),
makeNumericMinMax('Давление, атм', 'pressure'),
makeNumericMinMax('Момент на ВСП, кН·м', 'rotorTorque'),
makeNumericMinMax('Обороты на ВСП, об/мин', 'rotorSpeed'),
makeNumericMinMax('Расход, л/с', 'flow')
]
export const DrillProcessFlow = memo(() => {
const [flows, setFlows] = useState([])
const [showLoader, setShowLoader] = useState(false)
const [sectionTypes, setSectionTypes] = useState([])
const [well] = useWell()
const generateColumns = (sectionTypes = []) => [
makeNumericStartEnd('Глубина по стволу, м', 'depth', 1, null, null, null, '75px'),
makeSelectColumn('Секция', 'idWellSectionType', sectionTypes, null, {
editable: true,
width: '170px'
}),
makeDividedTextColumn('Операция бурения', null,
() => (
<div className='divided-cell'>
<span>Ротор</span>
<Divider className='cell-divider' />
<span>Слайд</span>
</div>
),
{ width: '70px' }
),
makeGroupColumn('АКБ', [
makeGroupColumn('Давление, атм', [
makeNumericDividedColumn('мин', 'pressureParams', null, null, {
input: React.createElement(({ value, onChange }) => (
<div className='divided-cell__edit'>
<InputNumber style={{ width: '100%' }} value={value?.rotorPressureMin} onChange={(e) => onChange({
...value,
rotorPressureMin: e,
})} />
<Divider className='cell-divider' />
<InputNumber style={{ width: '100%' }} value={value?.slidePressureMin} onChange={(e) => onChange({
...value,
slidePressureMin: e,
})} />
</div>
)),
render: (fieldValue, item) => (
<div className='divided-cell'>
<span>{formatCellValue(fieldValue?.rotorPressureMin)}</span>
<Divider className='cell-divider' />
<span>{formatCellValue(fieldValue?.slidePressureMin)}</span>
</div>
),
editable: true,
width: '107px'
}),
makeNumericDividedColumn('макс', 'pressureParams', null, null, {
input: React.createElement(({ value, onChange }) => (
<div className='divided-cell__edit'>
<InputNumber style={{ width: '100%' }} value={value?.rotorPressureMax} onChange={(e) => onChange({
...value,
rotorPressureMax: e,
})} />
<Divider className='cell-divider' />
<InputNumber style={{ width: '100%' }} value={value?.slidePressureMax} onChange={(e) => onChange({
...value,
slidePressureMax: e,
})} />
</div>
)),
render: (fieldValue, item) => (
<div className='divided-cell'>
<span>{formatCellValue(fieldValue?.rotorPressureMax)}</span>
<Divider className='cell-divider' />
<span>{formatCellValue(fieldValue?.slidePressureMax)}</span>
</div>
),
editable: true,
width: '107px',
}),
]),
makeGroupColumn('Нагрузка, т', [
makeNumericDividedColumn('мин', 'loadParams', null, null, {
input: React.createElement(({ value, onChange }) => (
<div className='divided-cell__edit'>
<InputNumber style={{ width: '100%' }} value={value?.rotorLoadMin} onChange={(e) => onChange({
...value,
rotorLoadMin: e,
})} />
<Divider className='cell-divider' />
<InputNumber style={{ width: '100%' }} value={value?.slideLoadMin} onChange={(e) => onChange({
...value,
slideLoadMin: e,
})} />
</div>
)),
render: (fieldValue, item) => (
<div className='divided-cell'>
<span>{formatCellValue(fieldValue?.rotorLoadMin)}</span>
<Divider className='cell-divider' />
<span>{formatCellValue(fieldValue?.slideLoadMin)}</span>
</div>
),
editable: true,
width: '107px',
}),
makeNumericDividedColumn('макс', 'loadParams', null, null, {
input: React.createElement(({ value, onChange }) => (
<div className='divided-cell__edit'>
<InputNumber style={{ width: '100%' }} value={value?.rotorLoadMax} onChange={(e) => onChange({
...value,
rotorLoadMax: e,
})} />
<Divider className='cell-divider' />
<InputNumber style={{ width: '100%' }} value={value?.slideLoadMax} onChange={(e) => onChange({
...value,
slideLoadMax: e,
})} />
</div>
)),
render: (fieldValue, item) => (
<div className='divided-cell'>
<span>{formatCellValue(fieldValue?.rotorLoadMax)}</span>
<Divider className='cell-divider' />
<span>{formatCellValue(fieldValue?.slideLoadMax)}</span>
</div>
),
editable: true,
width: '107px',
}),
]),
makeGroupColumn('Крутящий момент, кН*м', [
makeNumericDividedColumn('мин', 'torqueParams', null, null, {
input: React.createElement(({ value, onChange }) => (
<div className='divided-cell__edit'>
<InputNumber style={{ width: '100%' }} value={value?.rotorTorqueMin} onChange={(e) => onChange({
...value,
rotorTorqueMin: e,
})} />
<Divider className='cell-divider' />
<InputNumber style={{ width: '100%' }} readOnly={true} value={value?.slideTorqueMin} onChange={(e) => onChange({
...value,
slideTorqueMin: e,
})} />
</div>
)),
render: (fieldValue, item) => (
<div className='divided-cell'>
<span>{formatCellValue(fieldValue?.rotorTorqueMin)}</span>
<Divider className='cell-divider' />
<span>{formatCellValue(fieldValue?.slideTorqueMin)}</span>
</div>
),
editable: true,
width: '107px',
}),
makeNumericDividedColumn('макс', 'torqueParams', null, null, {
input: React.createElement(({ value, onChange }) => (
<div className='divided-cell__edit'>
<InputNumber style={{ width: '100%' }} value={value?.rotorTorqueMax} onChange={(e) => onChange({
...value,
rotorTorqueMax: e,
})} />
<Divider className='cell-divider' />
<InputNumber style={{ width: '100%' }} readOnly={true} value={value?.slideTorqueMax} onChange={(e) => onChange({
...value,
slideTorqueMax: e,
})} />
</div>
)),
render: (fieldValue, item) => (
<div className='divided-cell'>
<span>{formatCellValue(fieldValue?.rotorTorqueMax)}</span>
<Divider className='cell-divider' />
<span>{formatCellValue(fieldValue?.slideTorqueMax)}</span>
</div>
),
editable: true,
width: '107px',
}),
]),
makeGroupColumn('Расход, л/с', [
makeNumericDividedColumn('мин', 'flowParams', null, null, {
input: React.createElement(({ value, onChange }) => (
<div className='divided-cell__edit'>
<InputNumber style={{ width: '100%' }} value={value?.rotorFlowMin} onChange={(e) => onChange({
...value,
rotorFlowMin: e,
})} />
<Divider className='cell-divider' />
<InputNumber style={{ width: '100%' }} value={value?.slideFlowMin} onChange={(e) => onChange({
...value,
slideFlowMin: e,
})} />
</div>
)),
render: (fieldValue, item) => (
<div className='divided-cell'>
<span>{formatCellValue(fieldValue?.rotorFlowMin)}</span>
<Divider className='cell-divider' />
<span>{formatCellValue(fieldValue?.slideFlowMin)}</span>
</div>
),
editable: true,
width: '107px',
}),
makeNumericDividedColumn('макс', 'flowParams', null, null, {
input: React.createElement(({ value, onChange }) => (
<div className='divided-cell__edit'>
<InputNumber style={{ width: '100%' }} value={value?.rotorFlowMax} onChange={(e) => onChange({
...value,
rotorFlowMax: e,
})} />
<Divider className='cell-divider' />
<InputNumber style={{ width: '100%' }} value={value?.slideFlowMax} onChange={(e) => onChange({
...value,
slideFlowMax: e,
})} />
</div>
)),
render: (fieldValue, item) => (
<div className='divided-cell'>
<span>{formatCellValue(fieldValue?.rotorFlowMax)}</span>
<Divider className='cell-divider' />
<span>{formatCellValue(fieldValue?.slideFlowMax)}</span>
</div>
),
editable: true,
width: '107px',
}),
]),
makeNumericDividedColumn('Ограничение скорости, м/ч', 'speedLimitParams', null, null, {
input: React.createElement(({ value, onChange }) => (
<div className='divided-cell__edit'>
<InputNumber style={{ width: '100%' }} value={value?.rotorSpeedLimit} onChange={(e) => onChange({
...value,
rotorSpeedLimit: e,
})} />
<Divider className='cell-divider' />
<InputNumber style={{ width: '100%' }} value={value?.slideSpeedLimit} onChange={(e) => onChange({
...value,
slideSpeedLimit: e,
})} />
</div>
)),
render: (fieldValue, item) => (
<div className='divided-cell'>
<span>{formatCellValue(fieldValue?.rotorSpeedLimit)}</span>
<Divider className='cell-divider' />
<span>{formatCellValue(fieldValue?.slideSpeedLimit)}</span>
</div>
),
editable: true,
width: '130px',
}),
]),
makeGroupColumn('Spin Master', [
makeGroupColumn('Количество оборотов', [
makeNumericDividedColumn('мин', 'rpmParams', null, null, {
input: React.createElement(({ value, onChange }) => (
<div className='divided-cell__edit'>
<InputNumber style={{ width: '100%' }} readOnly={true} value={value?.rotorRpmMin} onChange={(e) => onChange({
...value,
rotorRpmMin: e,
})} />
<Divider className='cell-divider' />
<InputNumber style={{ width: '100%' }} value={value?.slideRpmMin} onChange={(e) => onChange({
...value,
slideRpmMin: e,
})} />
</div>
)),
render: (fieldValue, item) => (
<div className='divided-cell'>
<span>{formatCellValue(fieldValue?.rotorRpmMin)}</span>
<Divider className='cell-divider' />
<span>{formatCellValue(fieldValue?.slideRpmMin)}</span>
</div>
),
editable: true,
width: '107px',
}),
makeNumericDividedColumn('макс', 'rpmParams', null, null, {
input: React.createElement(({ value, onChange }) => (
<div className='divided-cell__edit'>
<InputNumber style={{ width: '100%' }} readOnly={true} value={value?.rotorRpmMax} onChange={(e) => onChange({
...value,
rotorRpmMax: e,
})} />
<Divider className='cell-divider' />
<InputNumber style={{ width: '100%' }} value={value?.slideRpmMax} onChange={(e) => onChange({
...value,
slideRpmMax: e,
})} />
</div>
)),
render: (fieldValue, item) => (
<div className='divided-cell'>
<span>{formatCellValue(fieldValue?.rotorRpmMax)}</span>
<Divider className='cell-divider' />
<span>{formatCellValue(fieldValue?.slideRpmMax)}</span>
</div>
),
editable: true,
width: '107px',
}),
]),
makeGroupColumn('Скорость вращения, об/мин', [
makeNumericDividedColumn('мин', 'speedParams', null, null, {
input: React.createElement(({ value, onChange }) => (
<div className='divided-cell__edit'>
<InputNumber style={{ width: '100%' }} readOnly={true} value={value?.rotorSpeedMin} onChange={(e) => onChange({
...value,
rotorSpeedMin: e,
})} />
<Divider className='cell-divider' />
<InputNumber style={{ width: '100%' }} value={value?.slideSpeedMin} onChange={(e) => onChange({
...value,
slideSpeedMin: e,
})} />
</div>
)),
render: (fieldValue, item) => (
<div className='divided-cell'>
<span>{formatCellValue(fieldValue?.rotorSpeedMin)}</span>
<Divider className='cell-divider' />
<span>{formatCellValue(fieldValue?.slideSpeedMin)}</span>
</div>
),
editable: true,
width: '107px',
}),
makeNumericDividedColumn('макс', 'speedParams', null, null, {
input: React.createElement(({ value, onChange }) => (
<div className='divided-cell__edit'>
<InputNumber style={{ width: '100%' }} readOnly={true} value={value?.rotorSpeedMax} onChange={(e) => onChange({
...value,
rotorSpeedMax: e,
})} />
<Divider className='cell-divider' />
<InputNumber style={{ width: '100%' }} value={value?.slideSpeedMax} onChange={(e) => onChange({
...value,
slideSpeedMax: e,
})} />
</div>
)),
render: (fieldValue, item) => (
<div className='divided-cell'>
<span>{formatCellValue(fieldValue?.rotorSpeedMax)}</span>
<Divider className='cell-divider' />
<span>{formatCellValue(fieldValue?.slideSpeedMax)}</span>
</div>
),
editable: true,
width: '107px',
}),
]),
]),
]
const columns = useMemo(() => generateColumns(sectionTypes), [sectionTypes])
useEffect(() => {
updateFlows()
}, [well])
const updateFlows = useCallback(() => invokeWebApiWrapperAsync(
async () => {
const sectionTypes = Object.entries(await WellOperationService.getSectionTypes(well.id) ?? {})
setSectionTypes(sectionTypes.map(([id, label]) => ({ value: parseInt(id), label })))
const flows = await DrillFlowChartService.getByIdWell(well.id)
setFlows(arrayOrDefault(flows))
},
@ -32,10 +377,6 @@ export const DrillProcessFlow = memo(() => {
{ actionName: 'Получение режимно-технологической карты', well }
), [well])
useEffect(() => {
updateFlows()
}, [well])
const tableHandlers = useMemo(() => {
const handlerProps = {
service: DrillFlowChartService,
@ -47,12 +388,20 @@ export const DrillProcessFlow = memo(() => {
const recordParser = (record) => ({ idWell: well.id, ...record })
return {
add: { ...handlerProps, action: 'insert', actionName: 'Добавление месторождения', recordParser },
edit: { ...handlerProps, action: 'update', actionName: 'Редактирование месторождения', recordParser },
delete: { ...handlerProps, action: 'delete', actionName: 'Удаление месторождения', permission: 'DrillFlowChart.delete' },
add: { ...handlerProps, action: 'insert', actionName: 'Добавление параметров для секции РТК', recordParser },
edit: { ...handlerProps, action: 'update', actionName: 'Редактирование параметров секции РТК', recordParser },
delete: { ...handlerProps, action: 'delete', actionName: 'Удаление параметров секции РТК', permission: 'DrillFlowChart.delete' },
}
}, [updateFlows, well.id])
const formatCellValue = (value) => {
let res = '-'
if ((value ?? null) !== null && Number.isFinite(+value)) {
res = (+value).toFixed(2)
}
return res
}
return (
<LoaderPortal show={showLoader}>
<EditableTable

View File

@ -17,7 +17,8 @@
@header-height: 64px;
@layout-min-height: calc(100vh - @header-height);
#root, .app{
#root,
.app {
min-height: 100%;
}
@ -116,6 +117,7 @@ html {
display: flex;
flex-direction: column;
align-items: stretch;
overflow: auto;
}
.sheet {
@ -160,3 +162,20 @@ tr.table_row_size {
margin-right: 5px;
margin-left: 5px;
}
.cell-divider {
margin: 0px 0px 0px -8px;
width: calc(100% + 16px);
}
.divided-cell {
height: 64px;
display: flex;
flex-direction: column;
justify-content: space-between;
&__edit {
.cell-divider {
margin: 8px 0px 8px -8px;
}
}
}