Переработана рекомендации уставок:

* Добавлена таблица с историей уставок
* Добавлено окно просмотра уставки
* Переработан стиль добавления уставки
This commit is contained in:
Александр Сироткин 2021-12-17 10:12:19 +05:00
parent 4d0627a4fa
commit ad8f01b186
3 changed files with 260 additions and 91 deletions

View File

@ -0,0 +1,113 @@
import { useState } from 'react'
import { Select, Modal, Input, InputNumber } from 'antd'
import { SetpointsService } from '../../services/api'
import LoaderPortal from '../../components/LoaderPortal'
import { invokeWebApiWrapperAsync } from '../../components/factory'
import { makeNumericRender, EditableTable, makeNumericInput } from '../../components/Table'
import { PeriodPicker, defaultPeriod } from '../../components/PeriodPicker'
import { Grid, GridItem } from '../../components/Grid'
export const SetpointSender = ({ idWell, onClose, visible, setpointNames }) => {
const [expirePeriod, setExpirePeriod] = useState(defaultPeriod)
const [comment, setComment] = useState('')
const [setpoints, setSetpoints] = useState([])
const [isLoading, setIsLoading] = useState(false)
const addingColumns = [
{
title: 'Наименование уставки',
dataIndex: 'name',
editable: true,
isRequired: true,
width: 200,
input: <Select options={setpointNames} />,
render: (val) => setpointNames.find((name) => name.value === val)?.label
}, {
title: 'Значение',
dataIndex: 'value',
editable: true,
isRequired: true,
width: 125,
input: <InputNumber style={{ width: '100%' }} formatter={value => `${value}`.replace(',', '.')}/>,
render: makeNumericRender(1),
align: 'right'
}
]
const onAdd = async (sp) => setSetpoints((prevSp) => {
sp.key = Date.now()
prevSp.push(sp)
return prevSp
})
const onEdit = async (sp) => setSetpoints((prevSp) => {
const idx = prevSp.findIndex((val) => val.key === sp.key)
prevSp[idx] = sp
return prevSp
})
const onDelete = async (sp) => setSetpoints((prevSp) => {
const idx = prevSp.findIndex((val) => val.key === sp.key)
prevSp.splice(idx, 1)
return prevSp
})
const onModalOk = () => invokeWebApiWrapperAsync(
async () => {
const setpointsObject = setpoints.reduce((obj, sp) => (obj[sp.name] = sp.value, obj), {})
const request = {
uploadDate: new Date(),
obsolescenceSec: expirePeriod,
setpoints: setpointsObject,
comment: comment
}
await SetpointsService.insert(idWell, request)
onClose(true)
},
setIsLoading,
`Не удалось отправить уставки по скважине "${idWell}"`
)
return (
<Modal
width={800}
title={'Рекомендовать уставки'}
visible={visible}
onCancel={onClose}
onOk={onModalOk}
okText={'Отправить'}
>
<LoaderPortal show={isLoading}>
<Grid>
<GridItem row={1} col={1}>Период актуальности рекомендаций:</GridItem>
<GridItem row={1} col={2}>
<PeriodPicker style={{ marginLeft: 'auto' }} onChange={setExpirePeriod} width={'100%'}/>
</GridItem>
<GridItem row={2} col={1}>Комментарий:</GridItem>
<GridItem row={3} col={1} colSpan={3}>
<Input.TextArea
rows={4}
onChange={(e) => setComment(e.target.value)}
value={comment}
required
/>
</GridItem>
<GridItem row={4} col={1} colSpan={3}>
<EditableTable
bordered
columns={addingColumns}
dataSource={setpoints}
onRowAdd={onAdd}
onRowEdit={onEdit}
onRowDelete={onDelete}
pagination={false}
style={{ margin: '10px 0' }}
/>
</GridItem>
</Grid>
</LoaderPortal>
</Modal>
)
}

View File

@ -0,0 +1,77 @@
import moment from 'moment'
import { memo } from 'react'
import { Modal, Input } from 'antd'
import { Table } from '../../components/Table'
import { UserView } from '../../components/UserView'
import { Grid, GridItem } from '../../components/Grid'
import { periodToString } from '../../utils/datetime'
export const setpointStatus = {
0: 'Неизвестно',
1: 'Ожидает отправки',
2: 'Отправлено',
3: 'Принято оператором',
4: 'Отклонено оператором',
5: 'Устарело',
}
export const getSetpointStatus = (id) => {
if (!id || Object.keys(setpointStatus).every((idx) => Number(idx) !== id))
return setpointStatus[0]
return setpointStatus[id]
}
const columns = [
{ title: 'Название', dataIndex: 'name' },
{ title: 'Значение', dataIndex: 'value' },
]
export const SetpointViewer = memo(({ setpoint, visible, onClose, setpointNames }) => {
let date = moment(setpoint?.uploadDate).format('DD MMM YYYY, HH:mm:ss')
let setpoints = []
if (setpoint) {
setpoints = Object.keys(setpoint?.setpoints).map((name) => ({
name: setpointNames.find(spName => spName.value === name)?.label,
value: setpoint.setpoints[name]
}))
}
return (
<Modal
width={800}
title={`Уставка от ${date}`}
onCancel={onClose}
visible={visible}
footer={null}
>
<Grid>
<GridItem row={1} col={1}>Дата рекомендаций:</GridItem>
<GridItem row={1} col={2}>{date}</GridItem>
<GridItem row={2} col={1}>Автор:</GridItem>
<GridItem row={2} col={2}><UserView user={setpoint?.author}/></GridItem>
<GridItem row={3} col={1}>Статус:</GridItem>
<GridItem row={3} col={2}>{getSetpointStatus(setpoint?.idState)}</GridItem>
<GridItem row={4} col={1}>Период актуальности рекомендаций:</GridItem>
<GridItem row={4} col={2}>{periodToString(setpoint?.obsolescenceSec)}</GridItem>
<GridItem row={5} col={1}>Комментарий:</GridItem>
<GridItem row={6} col={1} colSpan={3}>
<Input.TextArea rows={4} value={setpoint?.comment} readOnly />
</GridItem>
<GridItem row={7} col={1} colSpan={3}>
<Table
bordered
size={'small'}
dataSource={setpoints}
columns={columns}
pagination={false}
/>
</GridItem>
</Grid>
</Modal>
)
})

View File

@ -1,41 +1,25 @@
import { Button, Input, Modal, Select } from 'antd'
import { useState } from 'react'
import { invokeWebApiWrapperAsync } from '../../components/factory'
import moment from 'moment'
import { Button, Modal } from 'antd'
import { useState, useEffect } from 'react'
import { Table } from '../../components/Table'
import { UserView } from '../../components/UserView'
import LoaderPortal from '../../components/LoaderPortal'
import PeriodPicker, { defaultPeriod } from '../../components/PeriodPicker'
import { EditableTable, makeNumericRender } from '../../components/Table'
import { invokeWebApiWrapperAsync } from '../../components/factory'
import { makeStringCutter } from '../../utils/string'
import { SetpointsService } from '../../services/api'
import { SetpointSender } from './SetpointSender'
import { SetpointViewer, getSetpointStatus } from './SetpointViewer'
export const Setpoints = ({ idWell, ...other }) => {
const [isModalShown, setIsModalShown] = useState(false)
const [isModalVisible, setIsModalVisible] = useState(false)
const [isSenderVisible, setIsSenderVisible] = useState(false)
const [isViewerVisible, setIsViewerVisible] = useState(false)
const [isLoading, setIsLoading] = useState(false)
const [isUploading, setIsUploading] = useState(false)
const [setpointNames, setSetpointNames] = useState([])
const [setpoints, setSetpoints] = useState([])
const [comment, setComment] = useState('')
const [expirePeriod, setExpirePeriod] = useState(defaultPeriod)
const [selected, setSelected] = useState(null)
const [setpointNames, setSetpointNames] = useState([])
const columns = [
{
title: 'Наименование установки',
dataIndex: 'name',
editable: true,
isRequired: true,
width: 200,
input: <Select options={setpointNames} />,
render: (val) => setpointNames.find((name) => name.value === val)?.label
}, {
title: 'Значение',
dataIndex: 'value',
editable: true,
isRequired: true,
width: 125,
render: makeNumericRender(7),
align: 'right'
}
]
const onOpenClick = () => invokeWebApiWrapperAsync(
useEffect(() => invokeWebApiWrapperAsync(
async () => {
const names = await SetpointsService.getSetpointsNamesByIdWell(idWell)
if (!names) throw Error('Setpoints not found')
@ -44,84 +28,79 @@ export const Setpoints = ({ idWell, ...other }) => {
value: spn.name,
tooltip: spn.comment
})))
setIsModalShown(true)
},
setIsLoading,
`Не удалось загрузить список имёт уставок по скважине "${idWell}"`
), [idWell])
const showMore = (id) => {
const selected = setpoints.find((sp) => sp.id === id)
setSelected(selected ?? {})
setIsViewerVisible(true)
}
const historyColumns = [
{ title: 'Дата', dataIndex: 'uploadDate', render: item => moment(item).format('DD MMM YYYY, HH:mm:ss') },
{ title: 'Автор', dataIndex: 'author', render: (user) => <UserView user={user} /> },
{ title: 'Комментарий', dataIndex: 'comment', render: makeStringCutter() },
{ title: 'Статус', dataIndex: 'idState', render: (id) => getSetpointStatus(parseInt(id)) },
{ dataIndex: 'id', render: (id) => <Button onClick={() => showMore(id)}>Подробнее</Button> },
]
const updateTable = () => invokeWebApiWrapperAsync(
async () => {
const setpoints = await SetpointsService.getByIdWell(idWell)
setSetpoints(setpoints)
},
setIsLoading,
`Не удалось загрузить список для скважины "${idWell}"`
)
const onModalOk = () => invokeWebApiWrapperAsync(
async () => {
// eslint-disable-next-line no-sequences
const setpointsObject = setpoints.reduce((obj, sp) => (obj[sp.name] = sp.value, obj), {})
const request = {
uploadDate: new Date(),
obsolescenceSec: expirePeriod,
setpoints: setpointsObject,
comment: comment
useEffect(updateTable, [idWell])
const onSenderClose = (pushed) => {
if (pushed) updateTable()
setIsSenderVisible(false)
}
await SetpointsService.insert(idWell, request)
setIsModalShown(false)
},
setIsUploading,
`Не удалось отправить рекомендации по скважине "${idWell}"`
)
const onAdd = async (setpoint) => setSetpoints((prevSetpoints) => {
setpoint.key = Date.now()
prevSetpoints.push(setpoint)
return prevSetpoints
})
const onEdit = async (setpoint) => setSetpoints((prevSetpoints) => {
const idx = prevSetpoints.findIndex((val) => val.key === setpoint.key)
prevSetpoints[idx] = setpoint
return prevSetpoints
})
const onDelete = async (setpoint) => setSetpoints((prevSetpoints) => {
const idx = prevSetpoints.findIndex((val) => val.key === setpoint.key)
prevSetpoints.splice(idx, 1)
return prevSetpoints
})
return (
<div {...other}>
<Button onClick={onOpenClick} loading={isLoading}>
Рекомендовать установки
<Button onClick={() => setIsModalVisible(true)} loading={isLoading}>
Рекомендованные уставки
</Button>
<Modal
width={800}
title={'Рекомендация установок'}
visible={isModalShown}
onCancel={() => setIsModalShown(false)}
onOk={onModalOk}
okText={'Отправить'}
width={1200}
title={'Рекомендованные уставки'}
visible={isModalVisible}
onCancel={() => setIsModalVisible(false)}
footer={
<Button onClick={() => setIsSenderVisible(true)}>
Рекомендовать
</Button>
}
>
<LoaderPortal show={isUploading}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
Период актуальности рекомендаций:
<PeriodPicker onChange={setExpirePeriod} />
</div>
<EditableTable
<LoaderPortal show={isLoading}>
<Table
size={'small'}
bordered
columns={columns}
columns={historyColumns}
dataSource={setpoints}
onRowAdd={onAdd}
onRowEdit={onEdit}
onRowDelete={onDelete}
pagination={false}
style={{ margin: '10px 0' }}
/>
Комментарий:
<Input.TextArea
rows={4}
onChange={(e) => setComment(e.value)}
value={comment}
required
/>
</LoaderPortal>
</Modal>
<SetpointSender
idWell={idWell}
setpointNames={setpointNames}
visible={isSenderVisible}
onClose={onSenderClose}
/>
<SetpointViewer
setpointNames={setpointNames}
setpoint={selected}
visible={isViewerVisible}
onClose={() => setIsViewerVisible(false)}
/>
</div>
)
}