diff --git a/backend/app/services/task.py b/backend/app/services/task.py index e55cbe9..a971182 100644 --- a/backend/app/services/task.py +++ b/backend/app/services/task.py @@ -172,6 +172,7 @@ async def _run_on_device( device_row = await db.get(Device, device.id) if device_row: device_row.status = new_status + device_row.last_ping_at = finished_at if action_result_success: device_row.last_seen = finished_at ping_ms = (action_data or {}).get("ping_ms") diff --git a/frontend/src/pages/ObjectDetail.tsx b/frontend/src/pages/ObjectDetail.tsx index 47e9d01..0be2459 100644 --- a/frontend/src/pages/ObjectDetail.tsx +++ b/frontend/src/pages/ObjectDetail.tsx @@ -46,7 +46,7 @@ import { import { useRacks, useCreateRack, useUpdateRack, useDeleteRack, type RackItem } from '../api/racks' import { useZones, useCreateZone, useDeleteZone, type ZoneItem } from '../api/zones' import { useActions, useCreateTask, useTask } from '../api/tasks' -import { CategoryTag, DeviceStatusBadge } from '../components/StatusBadge' +import { CategoryTag } from '../components/StatusBadge' import { DeviceEditModal } from '../components/DeviceEditModal' import { DiscoveryDrawer } from '../components/DiscoveryDrawer' import { stripEmpty } from '../utils/form' @@ -72,9 +72,9 @@ type GroupRow = { type DeviceRow = DeviceItem & { _type: 'device' } type TableRow = GroupRow | DeviceRow -// Inventory cols: IP, Hostname, Rack, Category, Status, Ping, Source, Actions = 8 -// Work cols: IP, Hostname, Category, Status, Ping, Actions = 6 -const COL_SPAN: Record = { inventory: 8, work: 6 } +// Inventory cols: IP, Hostname, Rack, Category, Ping+Status, Source, Actions = 7 +// Work cols: IP, Hostname, Category, Ping+Status, Actions = 5 +const COL_SPAN: Record = { inventory: 7, work: 5 } function PingButton({ scope, @@ -419,56 +419,43 @@ export function ObjectDetailPage({ defaultMode = 'inventory' }: { defaultMode?: row._type === 'group' ? null : , }, { - title: 'Статус', - dataIndex: 'status', - key: 'status', - onCell: (row: TableRow) => row._type === 'group' ? { colSpan: 0 } : {}, - render: (_: unknown, row: TableRow) => - row._type === 'group' ? null : , - }, - { - title: 'Мониторинг', + title: 'Последний пинг', key: 'monitoring', - onCell: (row: TableRow) => row._type === 'group' ? { colSpan: 0 } : {}, + onCell: (row: TableRow) => { + if (row._type === 'group') return { colSpan: 0 } + const d = row as DeviceRow + const bg = + d.status === 'online' ? '#f6ffed' : + d.status === 'offline' ? '#fff2f0' : undefined + return bg ? { style: { background: bg } } : {} + }, render: (_: unknown, row: TableRow) => { if (row._type === 'group') return null const d = row as DeviceRow - // Нет никаких данных о пинге const pingTime = d.last_ping_at ?? d.last_seen if (!pingTime) { - if (!d.monitor_enabled) return выключен - return ожидание... + return ( + + {d.monitor_enabled ? 'ожидание...' : 'нет данных'} + + ) } const pauseIcon = !d.monitor_enabled ? : null - // Устройство online - if (d.status === 'online') { - return ( - - - - {dayjs(pingTime).format('DD.MM.YYYY HH:mm')} - - - {pauseIcon} - - ) - } - - // Устройство offline или unknown - // pingTime = последняя попытка (last_ping_at) или последний онлайн (last_seen как fallback) const lastSeenHint = d.last_seen && d.last_ping_at && d.last_ping_at !== d.last_seen ? `онлайн был: ${dayjs(d.last_seen).format('DD.MM.YYYY HH:mm')}` : null + const tooltipText = [elapsedAgo(pingTime), lastSeenHint].filter(Boolean).join(' · ') + return ( - - + + {dayjs(pingTime).format('DD.MM.YYYY HH:mm')}