feat: 性能优化 + 设备总览轨迹展示 + 广播指令API
性能: SQLite WAL模式、aiohttp Session复用、TCP连接锁+空闲超时、 device_id缓存、WebSocket并发广播、API Key认证缓存、围栏N+1查询 批量化、逆地理编码并行化、新增5个DB索引、日志降级DEBUG 功能: 广播指令API(broadcast)、exclude_type低精度后端过滤、 前端设备总览Tab+多设备轨迹叠加+高亮联动+搜索+专属颜色 via [HAPI](https://hapi.run) Co-Authored-By: HAPI <noreply@hapi.run>
This commit is contained in:
@@ -234,6 +234,19 @@ async def check_device_fences(
|
||||
"cell_id": cell_id,
|
||||
}
|
||||
|
||||
# 2. Batch-load all fence states in one query (avoid N+1)
|
||||
fence_ids = [f.id for f in fences]
|
||||
states_result = await session.execute(
|
||||
select(DeviceFenceState).where(
|
||||
DeviceFenceState.device_id == device_id,
|
||||
DeviceFenceState.fence_id.in_(fence_ids),
|
||||
)
|
||||
)
|
||||
states_map: dict[int, DeviceFenceState] = {s.fence_id: s for s in states_result.scalars().all()}
|
||||
|
||||
# Pre-check today's attendance dedup once (not per-fence)
|
||||
_today_clock_in = await _has_attendance_today(session, device_id, "clock_in")
|
||||
|
||||
tolerance = _get_tolerance_for_location_type(location_type)
|
||||
events: list[dict] = []
|
||||
now = now_cst()
|
||||
@@ -242,14 +255,7 @@ async def check_device_fences(
|
||||
for fence in fences:
|
||||
currently_inside = is_inside_fence(latitude, longitude, fence, tolerance)
|
||||
|
||||
# 2. Get or create state record
|
||||
state_result = await session.execute(
|
||||
select(DeviceFenceState).where(
|
||||
DeviceFenceState.device_id == device_id,
|
||||
DeviceFenceState.fence_id == fence.id,
|
||||
)
|
||||
)
|
||||
state = state_result.scalar_one_or_none()
|
||||
state = states_map.get(fence.id)
|
||||
|
||||
was_inside = bool(state and state.is_inside)
|
||||
|
||||
@@ -266,8 +272,8 @@ async def check_device_fences(
|
||||
_update_state(state, currently_inside, now, latitude, longitude)
|
||||
continue
|
||||
|
||||
# Daily dedup: only one clock_in per device per day
|
||||
if await _has_attendance_today(session, device_id, "clock_in"):
|
||||
# Daily dedup: only one clock_in per device per day (pre-fetched)
|
||||
if _today_clock_in:
|
||||
logger.info(
|
||||
"Fence skip clock_in: device=%d fence=%d(%s) already clocked in today",
|
||||
device_id, fence.id, fence.name,
|
||||
|
||||
Reference in New Issue
Block a user