feat: 位置追踪优化、考勤去重、围栏考勤补充设备信息

- 地图轨迹点按定位类型区分颜色 (GPS蓝/WiFi青/LBS橙/蓝牙紫)
- LBS/WiFi定位点显示精度圈 (虚线圆, LBS~1km/WiFi~80m)
- 地图图例显示各定位类型颜色和精度范围
- 精度圈添加 bubble:true 防止遮挡轨迹点点击
- 点击列表记录直接在地图显示Marker+弹窗 (无需先加载轨迹)
- 修复3D地图setZoomAndCenter坐标偏移, 改用setCenter+setZoom
- 最新位置轮询超时从15s延长至30s (适配LBS慢响应)
- 考勤每日去重: 同设备同类型每天只记录一条 (fence/device/bluetooth通用)
- 围栏自动考勤补充设备电量/信号/基站信息 (从Device表和位置包获取)
- 考勤来源字段 attendance_source 区分 device/bluetooth/fence

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>
This commit is contained in:
2026-03-30 04:26:29 +00:00
parent 1d06cc5415
commit 891344bfa0
8 changed files with 598 additions and 100 deletions

View File

@@ -1113,6 +1113,7 @@ class TCPManager:
fence_session, device_id_for_fence, imei,
latitude, longitude, location_type,
address, recorded_at,
mcc=mcc, mnc=mnc, lac=lac, cell_id=cell_id,
)
for evt in fence_events:
ws_manager.broadcast_nonblocking("fence_attendance", evt)
@@ -1873,10 +1874,23 @@ class TCPManager:
logger.warning("Attendance for unknown IMEI=%s", imei)
return attendance_type, reserved_bytes, datetime_bytes
# Determine attendance source from protocol
_att_source = "bluetooth" if proto == 0xB2 else "device"
# Daily dedup: one clock_in / clock_out per device per day
from app.services.fence_checker import _has_attendance_today
if await _has_attendance_today(session, device_id, attendance_type):
logger.info(
"Attendance dedup: IMEI=%s already has %s today, skip",
imei, attendance_type,
)
return attendance_type, reserved_bytes, datetime_bytes
record = AttendanceRecord(
device_id=device_id,
imei=conn_info.imei,
attendance_type=attendance_type,
attendance_source=_att_source,
protocol_number=proto,
gps_positioned=gps_positioned,
latitude=latitude,