Improved authentication; added fallbacks to 3D; cleaner dashboard charts

This commit is contained in:
iv_vuytsik
2025-10-22 21:28:10 +03:00
parent 34e84213c7
commit 932b16d4f4
18 changed files with 478 additions and 171 deletions

View File

@@ -215,28 +215,28 @@ const Dashboard: React.FC = () => {
title="Тренды детекторов"
subtitle="За последний месяц"
>
<DetectorChart type="line" />
<DetectorChart type="line" data={chartData?.map((d: any) => ({ value: d.value }))} />
</ChartCard>
<ChartCard
title="Статистика по месяцам"
subtitle="Активность детекторов"
>
<DetectorChart type="bar" />
<DetectorChart type="bar" data={chartData?.map((d: any) => ({ value: d.value }))} />
</ChartCard>
<ChartCard
title="Анализ производительности"
subtitle="Эффективность работы"
>
<DetectorChart type="line" />
<DetectorChart type="line" data={chartData?.map((d: any) => ({ value: d.value }))} />
</ChartCard>
<ChartCard
title="Сводка по статусам"
subtitle="Распределение состояний"
>
<DetectorChart type="bar" />
<DetectorChart type="bar" data={chartData?.map((d: any) => ({ value: d.value }))} />
</ChartCard>
</div>
</div>

View File

@@ -17,10 +17,11 @@ interface DetectorChartProps {
const DetectorChart: React.FC<DetectorChartProps> = ({
className = '',
data,
type = 'line'
}) => {
if (type === 'bar') {
const barData = [
const defaultBarData = [
{ value: 85, label: 'Янв' },
{ value: 70, label: 'Фев' },
{ value: 90, label: 'Мар' },
@@ -29,6 +30,13 @@ const DetectorChart: React.FC<DetectorChartProps> = ({
{ value: 95, label: 'Июн' }
]
const barData = (Array.isArray(data) && data.length > 0)
? data.slice(0, 6).map((d, i) => ({
value: d.value || 0,
label: d.label || defaultBarData[i]?.label || `${i + 1}`
}))
: defaultBarData
return (
<div className={`w-full h-full ${className}`}>
<svg className="w-full h-full" viewBox="0 0 400 200">
@@ -69,9 +77,40 @@ const DetectorChart: React.FC<DetectorChartProps> = ({
)
}
// Line chart implementation
const defaultLineData = [
{ value: 150 },
{ value: 120 },
{ value: 100 },
{ value: 80 },
{ value: 90 },
{ value: 70 },
{ value: 60 }
]
const lineData = (Array.isArray(data) && data.length > 0)
? data.slice(0, 7)
: defaultLineData
const maxVal = Math.max(...lineData.map(d => d.value || 0), 1)
const width = 400
const height = 200
const padding = 20
const plotHeight = height - 40
const stepX = lineData.length > 1 ? (width - 2 * padding) / (lineData.length - 1) : 0
const points = lineData.map((d, i) => {
const x = padding + i * stepX
const y = height - padding - ((d.value || 0) / maxVal) * plotHeight
return { x, y }
})
const linePath = points.map((p, i) => `${i === 0 ? 'M' : 'L'}${p.x},${p.y}`).join(' ')
const areaPath = `${linePath} L${width - padding},${height - padding} L${padding},${height - padding} Z`
return (
<div className={`w-full h-full ${className}`}>
<svg className="w-full h-full" viewBox="0 0 400 200">
<svg className="w-full h-full" viewBox={`0 0 ${width} ${height}`}>
<defs>
<linearGradient id="detectorGradient" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="rgb(231, 110, 80)" stopOpacity="0.3" />
@@ -79,22 +118,18 @@ const DetectorChart: React.FC<DetectorChartProps> = ({
</linearGradient>
</defs>
<path
d="M20,150 L80,120 L140,100 L200,80 L260,90 L320,70 L380,60 L380,180 L20,180 Z"
d={areaPath}
fill="url(#detectorGradient)"
/>
<path
d="M20,150 L80,120 L140,100 L200,80 L260,90 L320,70 L380,60"
d={linePath}
stroke="rgb(231, 110, 80)"
strokeWidth="2"
fill="none"
/>
<circle cx="20" cy="150" r="3" fill="rgb(231, 110, 80)" />
<circle cx="80" cy="120" r="3" fill="rgb(231, 110, 80)" />
<circle cx="140" cy="100" r="3" fill="rgb(231, 110, 80)" />
<circle cx="200" cy="80" r="3" fill="rgb(231, 110, 80)" />
<circle cx="260" cy="90" r="3" fill="rgb(231, 110, 80)" />
<circle cx="320" cy="70" r="3" fill="rgb(231, 110, 80)" />
<circle cx="380" cy="60" r="3" fill="rgb(231, 110, 80)" />
{points.map((p, i) => (
<circle key={i} cx={p.x} cy={p.y} r="3" fill="rgb(231, 110, 80)" />
))}
</svg>
</div>
)