Range editor update
parent
26276e0360
commit
61c623b93d
|
|
@ -1,4 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { statusConfig } from '../../Components/Layout/SettingsComponents/statusConfig';
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
|
|
@ -11,15 +12,6 @@ import {
|
||||||
Typography
|
Typography
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
|
|
||||||
// Используем те же цвета, что и в LineChartComponent
|
|
||||||
const statusColors = {
|
|
||||||
'0': '#757575', // серый (нет связи)
|
|
||||||
'1': '#4CAF50', // зеленый (норма)
|
|
||||||
'2': '#FFC107', // желтый (отклонение)
|
|
||||||
'3': '#FF9800', // оранжевый (критично)
|
|
||||||
'4': '#F44336' // красный (авария)
|
|
||||||
};
|
|
||||||
|
|
||||||
const StatusLogTable = ({ logs }) => {
|
const StatusLogTable = ({ logs }) => {
|
||||||
return (
|
return (
|
||||||
<TableContainer component={Paper} sx={{ mt: 2, maxHeight: 400 }}>
|
<TableContainer component={Paper} sx={{ mt: 2, maxHeight: 400 }}>
|
||||||
|
|
@ -44,10 +36,10 @@ const StatusLogTable = ({ logs }) => {
|
||||||
<TableCell>{log.source_id?.split('$')[1]}</TableCell>
|
<TableCell>{log.source_id?.split('$')[1]}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Chip
|
<Chip
|
||||||
label={getStatusText(log.status)}
|
label={statusConfig.getStatusText(log.status)}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: statusColors[log.status],
|
backgroundColor: statusConfig.getStatusColor(log.status),
|
||||||
color: '#ffffff', // белый текст для лучшей читаемости
|
color: '#ffffff',
|
||||||
fontWeight: 'bold',
|
fontWeight: 'bold',
|
||||||
border: 'none'
|
border: 'none'
|
||||||
}}
|
}}
|
||||||
|
|
@ -57,7 +49,7 @@ const StatusLogTable = ({ logs }) => {
|
||||||
<TableCell>{parseFloat(log.value).toFixed(2)}</TableCell>
|
<TableCell>{parseFloat(log.value).toFixed(2)}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Typography variant="body2">
|
<Typography variant="body2">
|
||||||
{log.description || getStatusDescription(log.status)}
|
{log.description || statusConfig.getStatusDescription(log.status)}
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|
@ -68,27 +60,4 @@ const StatusLogTable = ({ logs }) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Вспомогательные функции (оставляем без изменений)
|
|
||||||
const getStatusText = (status) => {
|
|
||||||
const statusMap = {
|
|
||||||
'0': 'Нет соединения',
|
|
||||||
'1': 'Норма',
|
|
||||||
'2': 'Отклонение',
|
|
||||||
'3': 'Критично',
|
|
||||||
'4': 'Авария'
|
|
||||||
};
|
|
||||||
return statusMap[status] || 'Неизвестно';
|
|
||||||
};
|
|
||||||
|
|
||||||
const getStatusDescription = (status) => {
|
|
||||||
const descriptions = {
|
|
||||||
'0': 'Устройство не отвечает',
|
|
||||||
'1': 'Параметры в норме',
|
|
||||||
'2': 'Обнаружены отклонения от нормы',
|
|
||||||
'3': 'Критическое состояние системы',
|
|
||||||
'4': 'Аварийное состояние системы'
|
|
||||||
};
|
|
||||||
return descriptions[status] || 'Статус неизвестен';
|
|
||||||
};
|
|
||||||
|
|
||||||
export default StatusLogTable;
|
export default StatusLogTable;
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
import React, { useState, useEffect, useCallback, useMemo } from 'react';
|
import React, { useState, useEffect, useCallback, useMemo } from 'react';
|
||||||
import {
|
import {
|
||||||
TextField, Box, Typography, IconButton, Divider,
|
TextField, Box, Typography, IconButton, Divider,
|
||||||
CircularProgress, Alert, Collapse, Tooltip, Button
|
CircularProgress, Alert, Collapse, Tooltip, Button, Select, MenuItem
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import DeleteIcon from '@mui/icons-material/Delete';
|
import DeleteIcon from '@mui/icons-material/Delete';
|
||||||
import AddIcon from '@mui/icons-material/Add';
|
import AddIcon from '@mui/icons-material/Add';
|
||||||
import SearchIcon from '@mui/icons-material/Search';
|
import SearchIcon from '@mui/icons-material/Search';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import { statusConfig } from './statusConfig';
|
||||||
import { VariableSizeList as List } from 'react-window';
|
import { VariableSizeList as List } from 'react-window';
|
||||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||||
|
|
||||||
|
|
@ -30,7 +31,7 @@ const MetricItem = React.memo(({ metric, index, updateRange, addRange, deleteRan
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
gap: 2,
|
gap: 2,
|
||||||
alignItems: 'center',
|
alignItems: 'flex-end', // Изменено с 'center' на 'flex-end'
|
||||||
mt: 1,
|
mt: 1,
|
||||||
'& > *': { flex: 1 }
|
'& > *': { flex: 1 }
|
||||||
}}
|
}}
|
||||||
|
|
@ -51,19 +52,38 @@ const MetricItem = React.memo(({ metric, index, updateRange, addRange, deleteRan
|
||||||
size="small"
|
size="small"
|
||||||
variant="standard"
|
variant="standard"
|
||||||
/>
|
/>
|
||||||
<TextField
|
<Select
|
||||||
label="Статус"
|
label="Статус"
|
||||||
type="number"
|
|
||||||
value={r.status}
|
value={r.status}
|
||||||
onChange={(e) => updateRange(index, j, 'status', e.target.value)}
|
onChange={(e) => updateRange(index, j, 'status', e.target.value)}
|
||||||
size="small"
|
size="small"
|
||||||
variant="standard"
|
variant="standard"
|
||||||
/>
|
sx={{
|
||||||
|
// Добавляем вертикальное выравнивание для label
|
||||||
|
'& .MuiInputLabel-root': {
|
||||||
|
transform: 'translate(0, -20px) scale(0.75)'
|
||||||
|
},
|
||||||
|
// Корректируем положение выбранного значения
|
||||||
|
'& .MuiSelect-select': {
|
||||||
|
paddingBottom: '8px'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{statusConfig.getAvailableStatuses().map(({ value, text }) => (
|
||||||
|
<MenuItem key={value} value={value}>
|
||||||
|
{text}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
<Tooltip title="Удалить диапазон">
|
<Tooltip title="Удалить диапазон">
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={() => deleteRange(index, j)}
|
onClick={() => deleteRange(index, j)}
|
||||||
size="small"
|
size="small"
|
||||||
sx={{ flex: 'none' }}
|
sx={{
|
||||||
|
flex: 'none',
|
||||||
|
// Корректируем положение иконки
|
||||||
|
marginBottom: '8px'
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<DeleteIcon fontSize="small" />
|
<DeleteIcon fontSize="small" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
|
@ -238,7 +258,6 @@ const MetricRangeEditor = ({ onSave }) => {
|
||||||
{!loading && (
|
{!loading && (
|
||||||
<>
|
<>
|
||||||
<Box sx={{ display: 'flex', alignItems: 'flex-end', gap: 1, mb: 2 }}>
|
<Box sx={{ display: 'flex', alignItems: 'flex-end', gap: 1, mb: 2 }}>
|
||||||
<SearchIcon sx={{ color: 'action.active', mr: 1 }} />
|
|
||||||
<TextField
|
<TextField
|
||||||
label="Поиск по метрике"
|
label="Поиск по метрике"
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|
@ -246,9 +265,15 @@ const MetricRangeEditor = ({ onSave }) => {
|
||||||
onChange={(e) => setFilter(e.target.value)}
|
onChange={(e) => setFilter(e.target.value)}
|
||||||
variant="standard"
|
variant="standard"
|
||||||
/>
|
/>
|
||||||
|
<SearchIcon sx={{ color: 'action.active', mr: 1 }} />
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box sx={{ display: 'flex', gap: 2, alignItems: 'center', mb: 3 }}>
|
<Box sx={{
|
||||||
|
display: 'flex',
|
||||||
|
gap: 2,
|
||||||
|
alignItems: 'flex-end', // меняем с 'center' на 'flex-end'
|
||||||
|
mb: 3
|
||||||
|
}}>
|
||||||
<TextField
|
<TextField
|
||||||
label="Новая метрика"
|
label="Новая метрика"
|
||||||
value={newMetricName}
|
value={newMetricName}
|
||||||
|
|
@ -262,7 +287,7 @@ const MetricRangeEditor = ({ onSave }) => {
|
||||||
color="primary"
|
color="primary"
|
||||||
disabled={!newMetricName.trim()}
|
disabled={!newMetricName.trim()}
|
||||||
>
|
>
|
||||||
<AddIcon />
|
<AddIcon sx={{ color: 'action.active' }} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
export const statusConfig = {
|
||||||
|
statusMap: {
|
||||||
|
'0': { text: 'Нет соединения', color: '#757575', description: 'Устройство не отвечает' },
|
||||||
|
'1': { text: 'Норма', color: '#4CAF50', description: 'Параметры в норме' },
|
||||||
|
'2': { text: 'Отклонение', color: '#FFC107', description: 'Обнаружены отклонения от нормы' },
|
||||||
|
'3': { text: 'Критично', color: '#FF9800', description: 'Критическое состояние системы' },
|
||||||
|
'4': { text: 'Авария', color: '#F44336', description: 'Аварийное состояние системы' }
|
||||||
|
},
|
||||||
|
|
||||||
|
getStatusText(status) {
|
||||||
|
return this.statusMap[status]?.text || 'Неизвестно';
|
||||||
|
},
|
||||||
|
|
||||||
|
getStatusColor(status) {
|
||||||
|
return this.statusMap[status]?.color || '#757575';
|
||||||
|
},
|
||||||
|
|
||||||
|
getStatusDescription(status) {
|
||||||
|
return this.statusMap[status]?.description || 'Статус неизвестен';
|
||||||
|
},
|
||||||
|
|
||||||
|
getAvailableStatuses() {
|
||||||
|
return Object.entries(this.statusMap)
|
||||||
|
.filter(([key]) => key !== '0') // исключаем статус "Нет соединения"
|
||||||
|
.map(([value, config]) => ({ value, text: config.text }));
|
||||||
|
}
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue