forked from ddrilling/asb_cloud_front
Merge branch 'dev' into feature/CF2-72-AdminPanel
This commit is contained in:
commit
df0fe53049
@ -16,10 +16,12 @@ const timePeriodCollection = [
|
||||
type PeriodPickerProps = {
|
||||
defaultValue?: number
|
||||
onChange?: (value: number) => void
|
||||
[other: string]: any
|
||||
}
|
||||
|
||||
export const PeriodPicker = ({ defaultValue = defaultPeriod, onChange }: PeriodPickerProps) => (
|
||||
export const PeriodPicker = ({ defaultValue = defaultPeriod, onChange, ...other }: PeriodPickerProps) => (
|
||||
<Select
|
||||
{...other}
|
||||
defaultValue={defaultValue}
|
||||
onChange={(value) => onChange?.(Number(value))}
|
||||
options={timePeriodCollection}
|
||||
|
@ -32,7 +32,7 @@ export const EditableCell = ({
|
||||
className={formItemClass}
|
||||
rules={formItemRules ?? [{
|
||||
required: isRequired,
|
||||
message: `Please Input ${title}!`,
|
||||
message: `Пожалуйста, введите ${title}!`,
|
||||
}]}
|
||||
initialValue={initialValue}
|
||||
>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { ReactNode } from 'react'
|
||||
import { Select, Table as RawTable } from 'antd'
|
||||
import { InputNumber, Select, Table as RawTable } from 'antd'
|
||||
import { OptionsType } from 'rc-select/lib/interface'
|
||||
import { tryAddKeys } from './EditableTable'
|
||||
import { makeNumericSorter, makeStringSorter} from './sorters'
|
||||
@ -143,7 +143,8 @@ export const makeNumericColumn = (
|
||||
onFilter: filterDelegate ? filterDelegate(dataIndex) : null,
|
||||
sorter: makeNumericSorter(dataIndex),
|
||||
width: width,
|
||||
render: renderDelegate??makeNumericRender(),
|
||||
input: <InputNumber style={{ width: '100%' }}/>,
|
||||
render: renderDelegate ?? makeNumericRender(),
|
||||
align: 'right',
|
||||
...other
|
||||
})
|
||||
|
@ -9,7 +9,7 @@ interface UserViewProps {
|
||||
|
||||
export const UserView = ({ user } : UserViewProps) => (user ? (
|
||||
<Tooltip title={(
|
||||
<Grid columnGap='8px'>
|
||||
<Grid style={{ columnGap: '8px' }}>
|
||||
<GridItem row={1} col={1}>Фамилия:</GridItem>
|
||||
<GridItem row={1} col={2}>{user?.surname}</GridItem>
|
||||
<GridItem row={2} col={1}>Имя:</GridItem>
|
||||
|
113
src/pages/TelemetryView/SetpointSender.jsx
Normal file
113
src/pages/TelemetryView/SetpointSender.jsx
Normal 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>
|
||||
)
|
||||
}
|
77
src/pages/TelemetryView/SetpointViewer.jsx
Normal file
77
src/pages/TelemetryView/SetpointViewer.jsx
Normal 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>
|
||||
)
|
||||
})
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ const blockHeightGroup = [
|
||||
color: '#333',
|
||||
showLabels: true
|
||||
}, {
|
||||
label: 'wellDepth',
|
||||
label: 'Глубина скважины',
|
||||
units: 'м',
|
||||
xAccessorName: 'wellDepth',
|
||||
yAccessorName: 'date',
|
||||
@ -59,7 +59,7 @@ const blockHeightGroup = [
|
||||
showLabels: true,
|
||||
showLine: true
|
||||
}, {
|
||||
label: 'flowLimits',
|
||||
label: 'Предел расхода',
|
||||
units: 'л/с',
|
||||
xAccessorName: 'flow',
|
||||
yAccessorName: 'date',
|
||||
@ -77,7 +77,7 @@ const blockSpeedGroup = [
|
||||
color: '#0a0',
|
||||
showLabels: true,
|
||||
}, {
|
||||
label: 'blockSpeedSp',
|
||||
label: 'Скорость заданная',
|
||||
units: 'м/ч',
|
||||
xAccessorName: 'blockSpeedSp',
|
||||
yAccessorName: 'date',
|
||||
@ -96,7 +96,7 @@ const pressureGroup = [
|
||||
color: '#c00',
|
||||
showLabels: true
|
||||
}, {
|
||||
label: 'pressureSp',
|
||||
label: 'Давление заданное',
|
||||
units: 'атм',
|
||||
xAccessorName: 'pressureSp',
|
||||
yAccessorName: 'date',
|
||||
@ -104,7 +104,7 @@ const pressureGroup = [
|
||||
footer: 'SP',
|
||||
dash
|
||||
}, {
|
||||
label: 'pressureIdle',
|
||||
label: 'Давление ХХ',
|
||||
units: 'атм',
|
||||
xAccessorName: 'pressureIdle',
|
||||
yAccessorName: 'date',
|
||||
@ -112,7 +112,7 @@ const pressureGroup = [
|
||||
footer: 'IDLE',
|
||||
dash
|
||||
}, {
|
||||
label: 'pressureDeltaLimitMax',
|
||||
label: 'Перепад давления максимальный',
|
||||
units: 'атм',
|
||||
xAccessorName: 'pressureDeltaLimitMax',
|
||||
yAccessorName: 'date',
|
||||
@ -120,7 +120,7 @@ const pressureGroup = [
|
||||
footer: true,
|
||||
dash
|
||||
}, {
|
||||
label: 'pressureLimits',
|
||||
label: 'Предел давления заданный',
|
||||
units: 'атм',
|
||||
xAccessorName: 'pressure',
|
||||
yAccessorName: 'date',
|
||||
@ -138,7 +138,7 @@ const axialLoadGroup = [
|
||||
color: '#00a',
|
||||
showLabels: true
|
||||
}, {
|
||||
label: 'axialLoadSp',
|
||||
label: 'Осевая нагрузка заданная',
|
||||
units: 'т',
|
||||
xAccessorName: 'axialLoadSp',
|
||||
yAccessorName: 'date',
|
||||
@ -146,7 +146,7 @@ const axialLoadGroup = [
|
||||
footer: 'SP',
|
||||
dash
|
||||
}, {
|
||||
label: 'axialLoadLimitMax',
|
||||
label: 'Осевая нагрузка максимальная',
|
||||
units: 'т',
|
||||
xAccessorName: 'axialLoadLimitMax',
|
||||
yAccessorName: 'date',
|
||||
@ -154,7 +154,7 @@ const axialLoadGroup = [
|
||||
footer: true,
|
||||
dash
|
||||
}, {
|
||||
label: 'axialLoadLimits',
|
||||
label: 'Пределы осевой нагрузки',
|
||||
units: 'т',
|
||||
xAccessorName: 'axialLoad',
|
||||
yAccessorName: 'date',
|
||||
@ -172,7 +172,7 @@ const hookWeightGroup = [
|
||||
color: '#0aa',
|
||||
showLabels: true
|
||||
}, {
|
||||
label: 'hookWeightIdle',
|
||||
label: 'Вес инструмента ХХ',
|
||||
units: 'т',
|
||||
xAccessorName: 'hookWeightIdle',
|
||||
yAccessorName: 'date',
|
||||
@ -180,7 +180,7 @@ const hookWeightGroup = [
|
||||
footer: 'IDLE',
|
||||
dash
|
||||
}, {
|
||||
label: 'hookWeightLimitMin',
|
||||
label: 'Вес инструмента минимальный',
|
||||
units: 'т',
|
||||
xAccessorName: 'hookWeightLimitMin',
|
||||
yAccessorName: 'date',
|
||||
@ -188,7 +188,7 @@ const hookWeightGroup = [
|
||||
footer: true,
|
||||
dash
|
||||
}, {
|
||||
label: 'hookWeightLimitMax',
|
||||
label: 'Вес инструмента максимальный',
|
||||
units: 'т',
|
||||
xAccessorName: 'hookWeightLimitMax',
|
||||
yAccessorName: 'date',
|
||||
@ -203,7 +203,7 @@ const hookWeightGroup = [
|
||||
color: '#aa0',
|
||||
showLabels: true
|
||||
}, {
|
||||
label: 'rotorSpeedLimits',
|
||||
label: 'Скорость вращения ВСП максимальная',
|
||||
units: 'об/мин',
|
||||
xAccessorName: 'rotorSpeed',
|
||||
yAccessorName: 'date',
|
||||
@ -237,7 +237,7 @@ const rotorTorqueGroup = [
|
||||
footer: 'IDLE',
|
||||
dash
|
||||
}, {
|
||||
label: 'rotorTorqueLimitMax',
|
||||
label: 'Момент максимальный',
|
||||
units: 'кН·м',
|
||||
xAccessorName: 'rotorTorqueLimitMax',
|
||||
yAccessorName: 'date',
|
||||
@ -245,7 +245,7 @@ const rotorTorqueGroup = [
|
||||
footer: true,
|
||||
dash
|
||||
}, {
|
||||
label: 'rotorTorqueLimits',
|
||||
label: 'Ограничения момента',
|
||||
units: 'кН·м',
|
||||
xAccessorName: 'rotorTorque',
|
||||
yAccessorName: 'date',
|
||||
|
10
src/utils/datetime.ts
Normal file
10
src/utils/datetime.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export const periodToString = (time?: number) => {
|
||||
if (!time) return '00:00:00'
|
||||
const hours = Math.floor(time / 3600)
|
||||
const minutes = Math.floor(time / 60 - hours * 60)
|
||||
const seconds = Math.floor(time - hours * 3600 - minutes * 60)
|
||||
|
||||
const toFixed = (num: number) => `${num}`.padStart(2, '0')
|
||||
|
||||
return `${toFixed(hours)}:${toFixed(minutes)}:${toFixed(seconds)}`
|
||||
}
|
8
src/utils/string.ts
Normal file
8
src/utils/string.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export const makeStringCutter = (maxLength = 100, separator = ' ', suffix = '...') => (comment?: string) => {
|
||||
if (!comment || comment.length < maxLength)
|
||||
return comment
|
||||
let lastSep = comment.lastIndexOf(separator, maxLength)
|
||||
if (lastSep < 0)
|
||||
return comment.substring(0, maxLength - suffix.length) + suffix
|
||||
return comment.substring(0, lastSep)
|
||||
}
|
Loading…
Reference in New Issue
Block a user