изменение пинга

This commit is contained in:
dv 2026-04-10 11:38:42 +03:00
parent e51e895d37
commit 4f5ab1a48b
6 changed files with 68 additions and 8 deletions

View file

@ -0,0 +1,25 @@
"""device last_ping_at
Revision ID: 0013
Revises: 0012
Create Date: 2026-04-10
"""
from alembic import op
import sqlalchemy as sa
revision = "0013"
down_revision = "0012"
branch_labels = None
depends_on = None
def upgrade() -> None:
op.add_column(
"devices",
sa.Column("last_ping_at", sa.DateTime(timezone=True), nullable=True),
)
def downgrade() -> None:
op.drop_column("devices", "last_ping_at")

View file

@ -78,6 +78,7 @@ class Device(Base, TimestampMixin):
# Monitoring # Monitoring
monitor_enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False) monitor_enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
last_ping_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
last_seen: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True) last_seen: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True)
last_ping_ms: Mapped[Optional[int]] = mapped_column(Integer, nullable=True) last_ping_ms: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
status: Mapped[str] = mapped_column(String(20), nullable=False, default="unknown") status: Mapped[str] = mapped_column(String(20), nullable=False, default="unknown")

View file

@ -81,6 +81,7 @@ class DeviceRead(BaseModel):
device_meta: dict[str, Any] = {} device_meta: dict[str, Any] = {}
capabilities: list[str] = [] capabilities: list[str] = []
monitor_enabled: bool monitor_enabled: bool
last_ping_at: Optional[datetime] = None
last_seen: Optional[datetime] = None last_seen: Optional[datetime] = None
last_ping_ms: Optional[int] = None last_ping_ms: Optional[int] = None
status: str status: str

View file

@ -112,6 +112,7 @@ async def _check_device(
return return
device.status = new_status device.status = new_status
device.last_ping_at = now
if success: if success:
device.last_seen = now device.last_seen = now
device.last_ping_ms = ping_ms device.last_ping_ms = ping_ms

View file

@ -49,9 +49,10 @@ export interface DeviceItem {
connection_params: Record<string, unknown> connection_params: Record<string, unknown>
capabilities: string[] capabilities: string[]
status: string status: string
monitor_enabled: boolean
last_ping_at: string | null
last_seen: string | null last_seen: string | null
last_ping_ms: number | null last_ping_ms: number | null
monitor_enabled: boolean
is_active: boolean is_active: boolean
notes: string | null notes: string | null
created_at: string created_at: string

View file

@ -427,19 +427,50 @@ export function ObjectDetailPage({ defaultMode = 'inventory' }: { defaultMode?:
row._type === 'group' ? null : <DeviceStatusBadge status={(row as DeviceRow).status} />, row._type === 'group' ? null : <DeviceStatusBadge status={(row as DeviceRow).status} />,
}, },
{ {
title: 'Последний ping', title: 'Мониторинг',
dataIndex: 'last_seen', key: 'monitoring',
key: 'last_seen',
onCell: (row: TableRow) => row._type === 'group' ? { colSpan: 0 } : {}, onCell: (row: TableRow) => row._type === 'group' ? { colSpan: 0 } : {},
render: (_: unknown, row: TableRow) => { render: (_: unknown, row: TableRow) => {
if (row._type === 'group') return null if (row._type === 'group') return null
const d = row as DeviceRow const d = row as DeviceRow
if (!d.last_seen) return '—'
// Мониторинг выключен и история отсутствует
if (!d.monitor_enabled && !d.last_ping_at) {
return <Typography.Text type="secondary">выключен</Typography.Text>
}
// Мониторинг включён, но ни разу не пинговалось
if (d.monitor_enabled && !d.last_ping_at) {
return <Typography.Text type="secondary">ожидание...</Typography.Text>
}
const pauseIcon = !d.monitor_enabled
? <Tooltip title="Мониторинг выключен"><span style={{ color: '#faad14', marginLeft: 4 }}></span></Tooltip>
: null
// Устройство online — last_ping_at ≈ last_seen
if (d.status === 'online') {
return (
<Tooltip title={elapsedAgo(d.last_ping_at!)}>
<span style={{ color: '#52c41a', cursor: 'default' }}>
{dayjs(d.last_ping_at).format('DD.MM.YYYY HH:mm')}
</span>
{pauseIcon}
</Tooltip>
)
}
// Устройство offline или unknown — показываем время попытки, в tooltip — когда был онлайн
const lastSeenHint = d.last_seen
? `онлайн был: ${dayjs(d.last_seen).format('DD.MM.YYYY HH:mm')}`
: 'онлайн не был'
return ( return (
<Tooltip title={elapsedAgo(d.last_seen)}> <Tooltip title={`${elapsedAgo(d.last_ping_at!)} · ${lastSeenHint}`}>
<span style={{ cursor: 'default' }}> <span style={{ color: '#ff4d4f', cursor: 'default' }}>
{dayjs(d.last_seen).format('DD.MM.YYYY HH:mm')} {dayjs(d.last_ping_at).format('DD.MM.YYYY HH:mm')}
</span> </span>
{pauseIcon}
</Tooltip> </Tooltip>
) )
}, },