пинг фикс

This commit is contained in:
dv 2026-04-09 15:07:15 +03:00
parent 21e21b87a8
commit b3119a81bd
4 changed files with 54 additions and 5 deletions

View file

@ -164,6 +164,32 @@ async def _run_on_device(
tr.data = action_data or None
tr.duration_ms = duration_ms
# For ping action: update device status, last_seen, last_ping_ms
if action.name == "ping":
new_status = "online" if action_result_success else "offline"
async with AsyncSessionLocal() as db:
async with db.begin():
device_row = await db.get(Device, device.id)
if device_row:
device_row.status = new_status
if action_result_success:
device_row.last_seen = finished_at
ping_ms = (action_data or {}).get("ping_ms")
if ping_ms is not None:
device_row.last_ping_ms = ping_ms
await sse_manager.publish(SSEEvent(
type="device_status",
task_id="__monitor__",
data={
"device_id": device.id,
"object_id": device.object_id,
"ip": device.ip,
"status": new_status,
"ping_ms": (action_data or {}).get("ping_ms") if action_result_success else None,
"ts": finished_at.isoformat(),
},
))
await sse_manager.publish(SSEEvent(
type="task_result",
task_id=task_id,

View file

@ -31,6 +31,7 @@ import { useNavigate, useParams } from 'react-router-dom'
import { useAlerts, useAcknowledgeAlert, useResolveAlert, type AlertItem } from '../api/alerts'
import { useDevice, useDeleteDevice, useObject } from '../api/objects'
import { getDeviceWebUrl } from '../utils/deviceUrl'
import { elapsedAgo } from '../utils/time'
import { useSnapshots, useSnapshotDiff } from '../api/snapshots'
import { useDeviceTasks, useTask, type Task } from '../api/tasks'
import { DeviceEditModal } from '../components/DeviceEditModal'
@ -463,10 +464,11 @@ export function DeviceDetailPage() {
<Descriptions.Item label="Статус"><DeviceStatusBadge status={effectiveStatus} /></Descriptions.Item>
<Descriptions.Item label="Последний ping">
{device.last_seen ? (
<Tooltip title={dayjs(device.last_seen).format('DD.MM.YYYY HH:mm:ss')}>
<Space size={4}>
<Tooltip title={elapsedAgo(device.last_seen)}>
<Space size={4} style={{ cursor: 'default' }}>
<ClockCircleOutlined style={{ color: '#999' }} />
<span>{effectivePing !== null ? `${effectivePing}мс` : '—'}</span>
<span>{dayjs(device.last_seen).format('DD.MM.YYYY HH:mm:ss')}</span>
{effectivePing !== null && <span style={{ color: '#999' }}>{effectivePing}мс</span>}
</Space>
</Tooltip>
) : '—'}

View file

@ -31,6 +31,7 @@ import { useDevices, useObject, type DeviceItem } from '../api/objects'
import { useRacks } from '../api/racks'
import { useActions, useCreateTask, useTask } from '../api/tasks'
import { CategoryTag, DeviceStatusBadge } from '../components/StatusBadge'
import { elapsedAgo } from '../utils/time'
import dayjs from 'dayjs'
function PingButton({
@ -256,8 +257,11 @@ export function WorkObjectDetailPage() {
if (row._type === 'group') return null
const d = row as DeviceRow
return d.last_seen ? (
<Tooltip title={dayjs(d.last_seen).format('DD.MM.YYYY HH:mm:ss')}>
<span>{d.last_ping_ms}ms</span>
<Tooltip title={elapsedAgo(d.last_seen)}>
<span style={{ cursor: 'default' }}>
{dayjs(d.last_seen).format('DD.MM.YYYY HH:mm:ss')}
{d.last_ping_ms != null ? <span style={{ color: '#999', marginLeft: 4 }}>{d.last_ping_ms}мс</span> : null}
</span>
</Tooltip>
) : '—'
},

View file

@ -0,0 +1,17 @@
/**
* Возвращает строку «сколько времени прошло» с момента date до сейчас.
* < 60 сек «N сек назад»
* < 60 мин «N мин назад»
* < 24 ч «N ч назад»
* иначе «N д назад»
*/
export function elapsedAgo(date: string | Date): string {
const diffMs = Date.now() - new Date(date).getTime()
const secs = Math.floor(diffMs / 1000)
if (secs < 60) return `${secs} сек назад`
const mins = Math.floor(secs / 60)
if (mins < 60) return `${mins} мин назад`
const hours = Math.floor(mins / 60)
if (hours < 24) return `${hours} ч назад`
return `${Math.floor(hours / 24)} д назад`
}