grouping Table components and functions into Table folder

This commit is contained in:
Фролов 2021-08-20 10:49:20 +05:00
parent 9d6669c160
commit a1173fb6a4
24 changed files with 289 additions and 284 deletions

View File

@ -1,5 +1,5 @@
import { ChartDepthToDay } from './charts/ChartDepthToDay'
import notify from "../components/notify"
import { notify } from "../components/factory"
import { useState, useEffect } from 'react'
import { TelemetryAnalyticsService } from "../services/api"
import LoaderPortal from '../components/LoaderPortal'

View File

@ -1,5 +1,5 @@
import { useParams } from "react-router-dom"
import notify from "../components/notify"
import { notify } from "../components/factory"
import { useState, useEffect } from 'react'
import { TelemetryAnalyticsService } from '../services/api'
import { ChartDepthToInterval } from './charts/ChartDepthToInterval'

View File

@ -1,6 +1,6 @@
import { useParams } from "react-router-dom"
import { DatePicker } from 'antd';
import notify from "../components/notify"
import { notify } from "../components/factory"
import { useState, useEffect } from 'react'
import { TelemetryAnalyticsService } from '../services/api'
import { ChartOperationTime } from './charts/ChartOperationTime'

View File

@ -0,0 +1,13 @@
import { DatePicker } from "antd"
import moment from "moment"
import {formatDate} from './index'
export const DatePickerWrapper = ({value, onChange, ...other}) => (<DatePicker
allowClear={false}
defaultValue={moment()}
value={moment.utc(value).local()}
format={formatDate}
showTime
onChange={(date) => onChange(date)}
{...other}
/>)

View File

@ -0,0 +1,34 @@
import { Form, Input} from "antd"
export const EditableCell = ({
editing,
record,
dataIndex,
input,
isRequired,
title,
formItemClass,
formItemRules,
children,
initialValue,
}) => {
const inputNode = input ?? <Input/>
const rules = formItemRules ?? [{
required: isRequired,
message: `Please Input ${title}!`,
}]
const editor = <Form.Item
name={dataIndex}
style={{margin:0}}
className={formItemClass}
rules={rules}
initialValue={initialValue}>
{inputNode}
</Form.Item>
return (<td>
{editing ? editor: children}
</td>)
}

View File

@ -1,42 +1,10 @@
import { Form, Input, Table, Button, Popconfirm } from "antd"
import { Form, Table, Button, Popconfirm } from "antd"
import { EditOutlined, SaveOutlined, PlusOutlined, CloseCircleOutlined, DeleteOutlined } from '@ant-design/icons'
import { useState, useEffect } from "react";
import { EditableCell } from './EditableCell'
const newRowKeyValue = 'newRow'
const EditableCell = ({
editing,
record,
dataIndex,
input,
isRequired,
title,
formItemClass,
formItemRules,
children,
initialValue,
}) => {
const inputNode = input ?? <Input/>
const rules = formItemRules ?? [{
required: isRequired,
message: `Please Input ${title}!`,
}]
const editor = <Form.Item
name={dataIndex}
style={{margin:0}}
className={formItemClass}
rules={rules}
initialValue={initialValue}>
{inputNode}
</Form.Item>
return (<td>
{editing ? editor: children}
</td>)
}
const tryAddKeys = (items) => {
if(!items?.length)
return []

View File

@ -0,0 +1,83 @@
export { EditableTable } from './EditableTable'
export { DatePickerWrapper } from './DatePickerWrapper'
export { Table } from 'antd'
export const RegExpIsFloat = /^[-+]?\d+\.?\d*$/
export const formatDate='YYYY.MM.DD HH:mm'
export const numericColumnOptions = {
editable: true,
initialValue: 0,
width:100,
formItemRules: [
{
required: true,
message: `Введите число`,
pattern: RegExpIsFloat,
},
],
};
/*
other - объект с дополнительными свойствами колонки
поддерживаются все базовые свойства из описания https://ant.design/components/table/#Column
плю дополнительные для колонок EditableTable:
editable - редактируемая колонка, bool
input - react компонента редактора (<Input/>, <InputNumber/>, <DatePickerWrapper/>...)
isRequired - значение может быть пустым,
formItemClass - css класс для <FormItem/>, если требуется
formItemRules - массив правил валидации значений https://ant.design/components/form/#Rule,
initialValue - дефолтное значение при добавлении новой строки
*/
export const makeColumn = (title:string, key:string, other?:any) => ({
title: title,
key: key,
dataIndex: key,
...other,
})
export const makeColumnsPlanFact = (title:string, key:string|string[], columsOther?:any|any[], gruopOther?:any) =>
{
let keyPlanLocal = key
let keyFactLocal = key
if(key instanceof Array){
keyPlanLocal = key[0]
keyFactLocal = key[1]
}else{
keyPlanLocal = key + 'Plan'
keyFactLocal = key + 'Fact'
}
let columsOtherLoacl :any[2]
if(columsOther instanceof Array)
columsOtherLoacl = [columsOther[0], columsOther[1]]
else
columsOtherLoacl = [columsOther, columsOther]
return {
title: title,
...gruopOther,
children: [
makeColumn('план', keyPlanLocal, columsOtherLoacl[0]),
makeColumn('факт', keyFactLocal, columsOtherLoacl[1]),
]
}
}
type PaginationContainer = {
skip?: number;
take?: number;
count?: number;
items?: any[] | null;
}
export const makePaginationObject = (paginationContainer:PaginationContainer, ...other:any) => {
let page = 1 + Math.floor((paginationContainer.skip??0) /(paginationContainer.take??1));
return {
...other,
pageSize: paginationContainer.take,
total: paginationContainer.count ?? paginationContainer.items?.length ?? 0,
current: page,
}
}

View File

@ -4,7 +4,7 @@ import { DepositService } from '../services/api'
import LoaderPortal from './LoaderPortal'
import { TreeSelect } from 'antd'
import { useHistory } from 'react-router-dom'
import notify from './notify'
import { notify } from "./factory"
import '../styles/wellTreeSelect.css'
export default function WellTreeSelector() {

View File

@ -1,90 +1,35 @@
import { Dispatch, SetStateAction } from "react"
import notify from "./notify"
import { notification } from 'antd';
export const RegExpIsFloat = /^[-+]?\d+\.?\d*$/
const notificationTypeDictionary = new Map([
['error', {notifyInstance: notification.error, caption: 'Ошибка'}],
['warning', {notifyInstance: notification.warning, caption: 'Предупреждение'}],
['info', {notifyInstance: notification.info, caption: 'Инфо'}],
['open', {notifyInstance: notification.info, caption: ''}],
])
/*
other - объект с дополнительными свойствами колонки
поддерживаются все базовые свойства из описания https://ant.design/components/table/#Column
плю дополнительные для колонок EditableTable:
editable - редактируемая колонка, bool
input - react компонента редактора (<Input/>, <InputNumber/>, <DatePicker/>...)
isRequired - значение может быть пустым,
formItemClass - css класс для <FormItem/>, если требуется
formItemRules - массив правил валидации значений https://ant.design/components/form/#Rule,
initialValue - дефолтное значение при добавлении новой строки
/**
* Вызов оповещений всплывающим окошком.
* @param body string или ReactNode
* @param notifyType для параметра типа. Допустимые значение 'error', 'warning', 'info'
*/
export const makeColumn = (title:string, key:string, other?:any) => ({
title: title,
key: key,
dataIndex: key,
...other,
})
export const notify = (body: string|any, notifyType:string ='info', other?: any) => {
if(!body)
return
const instance = notificationTypeDictionary.get(notifyType) ??
notificationTypeDictionary.get('open')
export const makeColumnsPlanFact = (title:string, key:string|string[], columsOther?:any|any[], gruopOther?:any) =>
{
let keyPlanLocal = key
let keyFactLocal = key
if(key instanceof Array){
keyPlanLocal = key[0]
keyFactLocal = key[1]
}else{
keyPlanLocal = key + 'Plan'
keyFactLocal = key + 'Fact'
}
let columsOtherLoacl :any[2]
if(columsOther instanceof Array)
columsOtherLoacl = [columsOther[0], columsOther[1]]
else
columsOtherLoacl = [columsOther, columsOther]
return {
title: title,
...gruopOther,
children: [
makeColumn('план', keyPlanLocal, columsOtherLoacl[0]),
makeColumn('факт', keyFactLocal, columsOtherLoacl[1]),
]
}
}
type PaginationContainer = {
skip?: number;
take?: number;
count?: number;
items?: any[] | null;
instance?.notifyInstance({
description: body,
message: instance.caption,
placement: "bottomRight",
duration: 10,
...other
})
}
type asyncFunction = (...args:any) => Promise<any|void>;
export const makePaginationObject = (paginationContainer:PaginationContainer, ...other:any) => {
let page = 1 + Math.floor((paginationContainer.skip??0) /(paginationContainer.take??1));
return {
...other,
pageSize: paginationContainer.take,
total: paginationContainer.count ?? paginationContainer.items?.length ?? 0,
current: page,
}
}
export const invokeWebApiWrapper = async (func: Function, setShowLoader: Dispatch<SetStateAction<boolean>>, errorNotifyText: string) => {
if(setShowLoader)
setShowLoader(true)
try{
func()
} catch (ex) {
if(process.env.NODE_ENV === 'development')
console.log(ex)
if(errorNotifyText)
notify(errorNotifyText, 'error')
} finally{
if(setShowLoader)
setShowLoader(false)
}
}
export const invokeWebApiWrapperAsync = async (funcAsync: asyncFunction, setShowLoader: Dispatch<SetStateAction<boolean>>, errorNotifyText: string) => {
if(setShowLoader)
setShowLoader(true)

View File

@ -1,10 +1,10 @@
import { useState, useEffect } from 'react';
import { useParams } from "react-router-dom";
import { Table, InputNumber, Form, Popconfirm, Typography, Button } from 'antd'
import { InputNumber, Form, Popconfirm, Typography, Button } from 'antd'
import LoaderPortal from '../LoaderPortal'
import { makeColumn } from '../factory'
import { makeColumn, Table } from '../Table'
import { FluidService } from '../../services/api/services/FluidService';
import notify from "../notify"
import { notify } from "../factory"
const EditableCell = ({
editing,

View File

@ -2,9 +2,9 @@ import { useState, useEffect } from 'react';
import { useParams } from "react-router-dom";
import { Table, InputNumber, Input, Form, Popconfirm, Typography, Button } from 'antd'
import LoaderPortal from '../LoaderPortal'
import { makeColumn } from '../factory'
import { makeColumn } from '../Table'
import { MudDiagramService } from '../../services/api/services/MudDiagramService'
import notify from "../notify"
import { notify } from "../factory"
const EditableCell = ({
editing,

View File

@ -2,9 +2,9 @@ import { useState, useEffect } from 'react'
import { useParams } from "react-router-dom";
import {Table, InputNumber, Form, Popconfirm, Typography, Button } from 'antd'
import LoaderPortal from '../LoaderPortal'
import { makeColumn } from '../factory'
import { makeColumn } from '../Table'
import { NnbDataService } from '../../services/api/services/NnbDataService';
import notify from "../notify"
import { notify } from "../factory"
const EditableCell = ({

View File

@ -1,24 +0,0 @@
import { notification } from 'antd';
const typeDictionary = {
'error': 'Ошибка',
'warning': 'Предупрежение',
'info': 'Информация'
}
/**
* Вызов оповещений всплывающим окошком.
* @param body string или ReactNode
* @param type для параметра типа. Допустимые значение 'error', 'warning', 'info'
*/
export default function notify(body, type='info'){
notification[type]({
description: body,
message: typeDictionary[type],
type,
placement: "bottomRight",
duration: 10,
})
}

View File

@ -10,7 +10,7 @@ import { DataService } from '../services/api'
import {generateUUID} from '../services/UidGenerator'
import { ArchiveColumn } from '../components/ArchiveColumn'
import moment from 'moment'
import notify from '../components/notify'
import { notify } from "../components/factory"
import LoaderPortal from '../components/LoaderPortal'
const { RangePicker } = DatePicker

View File

@ -3,7 +3,7 @@ import { Link } from "react-router-dom";
import LoaderPortal from '../components/LoaderPortal'
import { useState, useEffect } from "react";
import { ClusterService } from '../services/api'
import notify from '../components/notify'
import { notify } from "../components/factory"
import { Table, Tag, Button } from 'antd';
import ModalChartDepthToDay from '../components/modalWindows/ModalChartDepthToday'

View File

@ -3,7 +3,7 @@ import {Link} from "react-router-dom";
import LoaderPortal from '../components/LoaderPortal'
import { useState, useEffect } from "react";
import {ClusterService} from '../services/api'
import notify from '../components/notify'
import { notify } from "../components/factory"
import {Table, Tag, Button} from 'antd';
const columns = [

View File

@ -4,7 +4,7 @@ import {Link} from "react-router-dom";
import LoaderPortal from '../components/LoaderPortal'
import { useState, useEffect } from "react";
import {ClusterService} from '../services/api'
import notify from '../components/notify'
import { notify } from "../components/factory"
const calcViewParams = (clusters) => {
if ((!clusters) || clusters.length === 0)

View File

@ -5,9 +5,8 @@ import { FileService } from "../../services/api"
import {
invokeWebApiWrapperAsync,
download,
makePaginationObject,
} from "../../components/factory"
import { EditableTable } from "../../components/EditableTable"
import { EditableTable, makePaginationObject } from "../../components/Table"
import UploadForm from "../../components/UploadForm"
import LoaderPortal from "../../components/LoaderPortal"

View File

@ -4,7 +4,7 @@ import moment from 'moment'
import {MessageService} from '../services/api'
import LoaderPortal from '../components/LoaderPortal'
import notify from '../components/notify'
import { notify } from "../components/factory"
import '../styles/message.css'
const {Option} = Select

View File

@ -1,7 +1,5 @@
import { Progress } from "antd"
import { download } from "../../components/factory";
import notify from '../../components/notify'
import { download, notify } from "../../components/factory"
export const getReportFile = async (idWell, reportName) => {
try {

View File

@ -11,11 +11,10 @@ import {
import "moment/locale/ru"
import moment from "moment"
import { Subscribe } from "../../services/signalr"
import notify from "../../components/notify"
import LoaderPortal from "../../components/LoaderPortal"
import { ReportService } from "../../services/api"
import { ReportCreationNotify, getReportFile } from "./ReportCreationNotify"
import { invokeWebApiWrapperAsync } from "../../components/factory"
import { invokeWebApiWrapperAsync, notify} from "../../components/factory"
const { RangePicker } = DatePicker
const { Option } = Select

View File

@ -1,73 +1,82 @@
import {useEffect, useRef, useState} from 'react'
import { useEffect, useRef, useState } from "react";
import {
Chart,
TimeScale,
LinearScale,
Legend,
LineController,
PointElement,
LineElement,
} from 'chart.js'
import 'chartjs-adapter-moment'
import ChartDataLabels from 'chartjs-plugin-datalabels'
import zoomPlugin from 'chartjs-plugin-zoom'
import { invokeWebApiWrapper } from '../../components/factory'
import LoaderPortal from '../../components/LoaderPortal'
Chart,
TimeScale,
LinearScale,
Legend,
LineController,
PointElement,
LineElement,
} from "chart.js";
import "chartjs-adapter-moment";
import ChartDataLabels from "chartjs-plugin-datalabels";
import zoomPlugin from "chartjs-plugin-zoom";
import { invokeWebApiWrapperAsync } from "../../components/factory";
import LoaderPortal from "../../components/LoaderPortal";
//import { TvdService} from '../../services/api'
Chart.register(TimeScale, LinearScale, LineController, LineElement, PointElement, Legend, ChartDataLabels, zoomPlugin)
Chart.register(
TimeScale,
LinearScale,
LineController,
LineElement,
PointElement,
Legend,
ChartDataLabels,
zoomPlugin
);
const defaultOptions = {
responsive: true,
aspectRatio: 2.35,
interaction: {
intersect: false,
mode: 'index',
mode: "index",
},
scales: {
x:{
x: {
display: true,
title: {
display: true
display: true,
},
type: 'linear', // был 'time' + его конфиг ниже
grid:{
type: "linear", // был 'time' + его конфиг ниже
grid: {
drawTicks: true,
},
ticks: {
//count:24,
stepSize:3,
major:{enabled:true,},
stepSize: 3,
major: { enabled: true },
z: 1,
display : true,
textStrokeColor : "#fff",
textStrokeWidth : 2,
color:"#000",
}
display: true,
textStrokeColor: "#fff",
textStrokeWidth: 2,
color: "#000",
},
},
y:{
type:'linear',
position:'top',
reverse:true,
y: {
type: "linear",
position: "top",
reverse: true,
display: true,
title: {
display: true,
text: 'Value'
text: "Value",
},
}
},
parsing: {
xAxisKey: 'date',
yAxisKey: 'depth'
},
elements:{
point:{
radius:1.7,
},
},
plugins:{
legend:{
parsing: {
xAxisKey: "date",
yAxisKey: "depth",
},
elements: {
point: {
radius: 1.7,
},
},
plugins: {
legend: {
display: true,
},
datalabels: {
@ -77,67 +86,73 @@ const defaultOptions = {
enabled: true,
callbacks: {
label(tooltipItem) {
return tooltipItem.yLabel
}
}
return tooltipItem.yLabel;
},
},
},
}
}
},
};
const makeDataset = (data, label, color, width=1.5, dash) => ({
const makeDataset = (data, label, color, width = 1.5, dash) => ({
label: label,
data: data,
backgroundColor: color,
borderColor: color,
borderWidth: width,
borderDash: dash,
})
});
export const Tvd = ({idWell}) =>{
const chartRef = useRef(null)
const [chart, setChart] = useState()
const [data, setData] = useState({datasets: []})
const [showLoader, setShowLoader] = useState(false)
export const Tvd = ({ idWell }) => {
const chartRef = useRef(null);
const [chart, setChart] = useState();
const [data, setData] = useState({ datasets: [] });
const [showLoader, setShowLoader] = useState(false);
useEffect(() => invokeWebApiWrapper(
async() => {
const dataPlan = []
const dataFact = []
const dataPredict = []
const data = {
datasets: [
makeDataset(dataPlan, 'План', '#C004', 4),
makeDataset(dataFact, 'Факт', '#0A0'),
makeDataset(dataPredict, 'Прогноз', 'purple', 1, [7,3]),
]
}
setData(data)
},
setShowLoader,
`Не удалось загрузить данные TVD по скважине ${idWell}`),
[idWell])
useEffect(
() =>
invokeWebApiWrapperAsync(
async () => {
const dataPlan = [];
const dataFact = [];
const dataPredict = [];
const data = {
datasets: [
makeDataset(dataPlan, "План", "#C004", 4),
makeDataset(dataFact, "Факт", "#0A0"),
makeDataset(dataPredict, "Прогноз", "purple", 1, [7, 3]),
],
};
setData(data);
},
setShowLoader,
`Не удалось загрузить данные TVD по скважине ${idWell}`
),
[idWell]
);
useEffect(() => {
if((chartRef.current)&&(!chart)) {
let thisOptions = {}
Object.assign(thisOptions, defaultOptions)
useEffect(() => {
if (chartRef.current && !chart) {
let thisOptions = {};
Object.assign(thisOptions, defaultOptions);
let newChart = new Chart(chartRef.current, {
type: 'line',
plugins: [ChartDataLabels],
options: thisOptions,
data: data
})
setChart(newChart)
let newChart = new Chart(chartRef.current, {
type: "line",
plugins: [ChartDataLabels],
options: thisOptions,
data: data,
});
setChart(newChart);
return () => chart?.destroy()
}else{
chart.data = data
chart.update()
return () => chart?.destroy();
} else {
chart.data = data;
chart.update();
}
}, [chart, data])
}, [chart, data]);
return <LoaderPortal show={showLoader}>
<canvas ref={chartRef} />
</LoaderPortal>
}
return (
<LoaderPortal show={showLoader}>
<canvas ref={chartRef} />
</LoaderPortal>
);
};

View File

@ -1,9 +1,9 @@
import { useState, useEffect } from 'react'
import { Input, DatePicker, Select } from 'antd'
import { Input, Select } from 'antd'
import moment from 'moment'
import { EditableTable } from "../../components/EditableTable"
import { EditableTable, DatePickerWrapper, numericColumnOptions, makeColumn } from "../../components/Table"
import LoaderPortal from '../../components/LoaderPortal'
import { makeColumn, RegExpIsFloat, invokeWebApiWrapperAsync } from '../../components/factory'
import { invokeWebApiWrapperAsync } from '../../components/factory'
import { WellOperationService} from '../../services/api'
import { dictionarySectionType, getNameById } from './dictionary'
@ -13,31 +13,6 @@ const { TextArea } = Input;
const basePageSize = 160;
const format='YYYY.MM.DD HH:mm'
const numericColumnOptions = {
editable: true,
initialValue: 0,
width:100,
formItemRules: [
{
required: true,
message: `Введите число`,
pattern: RegExpIsFloat,
},
],
};
const DatePickerWrapper = ({value, onChange, ...other}) => {
return <DatePicker
allowClear={false}
defaultValue={moment()}
value={moment.utc(value).local()}
format={format}
showTime
onChange={(date) => onChange(date)}
{...other}
/>
}
export const WellOperationsEditor = ({idWell, idType}) => {
const [pageNumAndPageSize, setPageNumAndPageSize] = useState({current:1, pageSize:basePageSize})
const [paginationTotal, setPaginationTotal] = useState(0)
@ -97,14 +72,14 @@ export const WellOperationsEditor = ({idWell, idType}) => {
render:(_, record)=>getNameById(dictionaryOperationCategory, record.idCategory)
}),
makeColumn('Доп. инфо','categoryInfo', {editable:true, width:300, input:<TextArea/>}),
makeColumn('Глубина забоя','wellDepth', {...numericColumnOptions}),
makeColumn('Глубина забоя','wellDepth', numericColumnOptions),
makeColumn('Время начала','startDate', {
editable:true,
width:200,
input:<DatePickerWrapper/>,
render:(_, record) => moment.utc(record.startDate).local().format(format)
}),
makeColumn('Часы','durationHours', {...numericColumnOptions}),
makeColumn('Часы','durationHours', numericColumnOptions),
makeColumn('Комментарий','comment', {editable:true, input:<TextArea/>}),
]

View File

@ -1,7 +1,7 @@
import { useState, useEffect } from 'react'
import { Table } from 'antd'
import LoaderPortal from '../../components/LoaderPortal'
import { makeColumn, makeColumnsPlanFact, invokeWebApiWrapperAsync } from '../../components/factory'
import { invokeWebApiWrapperAsync } from '../../components/factory'
import { Table, makeColumn, makeColumnsPlanFact } from '../../components/Table'
import { WellSectionService } from '../../services/api'
const makeNumberRender = (format) => ((value) => (+value).toFixed(format))