forked from BLC/AyposWeb
274 lines
9.2 KiB
TypeScript
274 lines
9.2 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import { Box, Paper, Typography, Fade, useTheme, AppBar, Toolbar, Chip } from '@mui/material';
|
|
import { LineChart } from '@mui/x-charts/LineChart';
|
|
import { config } from '../config/env';
|
|
|
|
interface DataItem {
|
|
now_timestamp: string;
|
|
future_timestamp: string;
|
|
power: string;
|
|
power_future_min: string;
|
|
positive_3p: string;
|
|
negative_3p: string;
|
|
positive_7p: string;
|
|
negative_7p: string;
|
|
flag: string;
|
|
}
|
|
|
|
const API_BASE_URL = config.apiUrl;
|
|
|
|
const Maintenance = () => {
|
|
const theme = useTheme();
|
|
|
|
const [data, setData] = useState<DataItem[]>([]);
|
|
const [currentFlag, setCurrentFlag] = useState<string>('');
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
const fetchData = async () => {
|
|
try {
|
|
setLoading(true);
|
|
const response = await fetch(`${API_BASE_URL}/prom/get_chart_data/maintenance/20`);
|
|
const result = await response.json();
|
|
|
|
if (result.data && result.data.length > 0) {
|
|
const last20Data = result.data.slice(-20);
|
|
setCurrentFlag(last20Data[last20Data.length - 1].flag);
|
|
setData(last20Data);
|
|
console.log('Fetched data:', last20Data);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching data:', error);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
fetchData();
|
|
const interval = setInterval(fetchData, 5000);
|
|
return () => clearInterval(interval);
|
|
}, []);
|
|
|
|
// Process data for charts
|
|
const prepareChartData = () => {
|
|
if (!data || data.length === 0) {
|
|
console.log('No data available, using fallback data');
|
|
// Fallback data for testing
|
|
const now = new Date();
|
|
const fallbackData = Array.from({ length: 10 }, (_, i) => ({
|
|
currentTimestamp: new Date(now.getTime() - (9 - i) * 60000), // 1 minute intervals
|
|
futureTimestamp: new Date(now.getTime() - (9 - i) * 60000 + 3 * 60000), // 3 minutes in the future
|
|
currentPower: 95 + Math.random() * 10,
|
|
predictedPower: 115 + Math.random() * 10,
|
|
positive3p: 118 + Math.random() * 5,
|
|
negative3p: 112 + Math.random() * 5,
|
|
positive7p: 123 + Math.random() * 5,
|
|
negative7p: 107 + Math.random() * 5,
|
|
}));
|
|
return fallbackData;
|
|
}
|
|
|
|
const processedData = data.map(item => {
|
|
const currentPower = parseFloat(item.power) || 0;
|
|
const predictedPower = parseFloat(item.power_future_min) || currentPower * 1.1; // Fallback to 10% higher than current
|
|
|
|
return {
|
|
currentTimestamp: new Date(item.now_timestamp),
|
|
futureTimestamp: new Date(item.future_timestamp),
|
|
currentPower: currentPower,
|
|
predictedPower: predictedPower,
|
|
positive3p: parseFloat(item.positive_3p) || predictedPower * 1.03,
|
|
negative3p: parseFloat(item.negative_3p) || predictedPower * 0.97,
|
|
positive7p: parseFloat(item.positive_7p) || predictedPower * 1.07,
|
|
negative7p: parseFloat(item.negative_7p) || predictedPower * 0.93,
|
|
};
|
|
});
|
|
|
|
console.log('Processed chart data:', processedData);
|
|
console.log('Data validation:', {
|
|
hasCurrentPower: processedData.some(d => d.currentPower > 0),
|
|
hasPredictedPower: processedData.some(d => d.predictedPower > 0),
|
|
currentPowerRange: [Math.min(...processedData.map(d => d.currentPower)), Math.max(...processedData.map(d => d.currentPower))],
|
|
predictedPowerRange: [Math.min(...processedData.map(d => d.predictedPower)), Math.max(...processedData.map(d => d.predictedPower))],
|
|
rawDataSample: data.slice(0, 2).map(item => ({
|
|
power: item.power,
|
|
power_future_min: item.power_future_min,
|
|
parsedCurrent: parseFloat(item.power),
|
|
parsedPredicted: parseFloat(item.power_future_min)
|
|
}))
|
|
});
|
|
return processedData;
|
|
};
|
|
|
|
const chartData = prepareChartData();
|
|
|
|
// Extract data arrays for charts
|
|
const currentTimestamps = chartData.map(item => item.currentTimestamp);
|
|
const futureTimestamps = chartData.map(item => item.futureTimestamp);
|
|
|
|
const currentPowerData = chartData.map(item => item.currentPower);
|
|
const predictedPowerData = chartData.map(item => item.predictedPower);
|
|
const positive3pData = chartData.map(item => item.positive3p);
|
|
const negative3pData = chartData.map(item => item.negative3p);
|
|
const positive7pData = chartData.map(item => item.positive7p);
|
|
const negative7pData = chartData.map(item => item.negative7p);
|
|
|
|
// Debug logging
|
|
console.log('Chart arrays:', {
|
|
currentTimestamps: currentTimestamps.length,
|
|
futureTimestamps: futureTimestamps.length,
|
|
currentPower: currentPowerData.length,
|
|
predictedPower: predictedPowerData.length,
|
|
positive3p: positive3pData.length,
|
|
negative3p: negative3pData.length,
|
|
positive7p: positive7pData.length,
|
|
negative7p: negative7pData.length,
|
|
});
|
|
console.log('Sample timestamps:', {
|
|
current: currentTimestamps.slice(0, 3),
|
|
future: futureTimestamps.slice(0, 3),
|
|
currentPower: currentPowerData.slice(0, 3),
|
|
predictedPower: predictedPowerData.slice(0, 3),
|
|
});
|
|
|
|
return (
|
|
<Box sx={{ flexGrow: 1, bgcolor: theme.palette.background.default }}>
|
|
<AppBar
|
|
position="static"
|
|
elevation={0}
|
|
sx={{
|
|
bgcolor: 'background.paper',
|
|
borderBottom: `1px solid ${theme.palette.divider}`,
|
|
mb: 3
|
|
}}
|
|
>
|
|
<Toolbar sx={{ px: { xs: 2, sm: 4 } }}>
|
|
<Typography
|
|
variant="h5"
|
|
component="h1"
|
|
sx={{
|
|
color: 'text.primary',
|
|
fontWeight: 500,
|
|
flex: 1,
|
|
textAlign: 'center',
|
|
letterSpacing: '-0.5px'
|
|
}}
|
|
>
|
|
Preventive Maintenance
|
|
</Typography>
|
|
{currentFlag && (
|
|
<Chip
|
|
label={currentFlag}
|
|
color={currentFlag === 'Correct Estimation for PM energy' ? 'success' : 'warning'}
|
|
size="medium"
|
|
sx={{
|
|
height: 32,
|
|
'& .MuiChip-label': {
|
|
px: 2,
|
|
fontSize: '0.875rem',
|
|
fontWeight: 600
|
|
},
|
|
animation: 'pulse 2s infinite',
|
|
'@keyframes pulse': {
|
|
'0%': {
|
|
boxShadow: '0 0 0 0 rgba(0, 0, 0, 0.2)',
|
|
},
|
|
'70%': {
|
|
boxShadow: '0 0 0 6px rgba(0, 0, 0, 0)',
|
|
},
|
|
'100%': {
|
|
boxShadow: '0 0 0 0 rgba(0, 0, 0, 0)',
|
|
},
|
|
}
|
|
}}
|
|
/>
|
|
)}
|
|
</Toolbar>
|
|
</AppBar>
|
|
|
|
<Box sx={{ p: { xs: 2, sm: 4 } }}>
|
|
<Fade in timeout={800}>
|
|
<Paper
|
|
elevation={0}
|
|
sx={{
|
|
p: { xs: 2, sm: 3 },
|
|
bgcolor: 'background.paper',
|
|
borderRadius: 2,
|
|
border: `1px solid ${theme.palette.divider}`,
|
|
}}
|
|
>
|
|
<Box sx={{ height: 'calc(100vh - 200px)', minHeight: '500px' }}>
|
|
<LineChart
|
|
height={500}
|
|
skipAnimation={false}
|
|
series={[
|
|
{
|
|
data: currentPowerData,
|
|
label: 'Current Power',
|
|
color: '#028a4a', // B'GREEN brand color
|
|
showMark: true,
|
|
curve: 'linear'
|
|
},
|
|
{
|
|
data: predictedPowerData,
|
|
label: 'Predicted (3min)',
|
|
color: '#ff9800',
|
|
showMark: true,
|
|
curve: 'linear'
|
|
},
|
|
{
|
|
data: positive3pData,
|
|
label: '+3% Positive',
|
|
color: '#2ca02c',
|
|
showMark: false
|
|
},
|
|
{
|
|
data: negative3pData,
|
|
label: '-3% Negative',
|
|
color: '#d62728',
|
|
showMark: false
|
|
},
|
|
{
|
|
data: positive7pData,
|
|
label: '+7% Positive',
|
|
color: '#9467bd',
|
|
showMark: false
|
|
},
|
|
{
|
|
data: negative7pData,
|
|
label: '-7% Negative',
|
|
color: '#8c564b',
|
|
showMark: false
|
|
},
|
|
]}
|
|
xAxis={[
|
|
{
|
|
scaleType: 'time',
|
|
data: [...currentTimestamps, ...futureTimestamps],
|
|
valueFormatter: (value: Date) => value.toLocaleTimeString(),
|
|
},
|
|
]}
|
|
yAxis={[
|
|
{
|
|
width: 50,
|
|
valueFormatter: (value: number) => `${value} W`,
|
|
}
|
|
]}
|
|
margin={{ right: 24 }}
|
|
slotProps={{
|
|
legend: {
|
|
direction: 'horizontal',
|
|
position: { vertical: 'top', horizontal: 'center' },
|
|
},
|
|
}}
|
|
/>
|
|
</Box>
|
|
</Paper>
|
|
</Fade>
|
|
</Box>
|
|
</Box>
|
|
);
|
|
};
|
|
|
|
export default Maintenance;
|