```
feat(auth): 添加用户权限获取接口并完善JWT令牌角色信息 - 在JWT令牌中添加用户角色信息 - 新增get_my_permissions接口用于获取当前用户权限码列表 - 重构认证回调逻辑,增加错误日志记录 - 更新用户信息获取接口使用Authorization头验证 ```
This commit is contained in:
+146
-16
@@ -3,14 +3,18 @@ from fastapi import APIRouter, Depends
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import func, case
|
||||
from app.core.database import get_db
|
||||
from app.models.device import ONUDevice, DeviceStatusHistory
|
||||
from datetime import datetime, timedelta
|
||||
from app.middleware.permission_middleware import require_permission
|
||||
from app.models.device import ONUDevice, DeviceStatusHistory, DeviceDailySnapshot
|
||||
from datetime import datetime, timedelta, date
|
||||
|
||||
router = APIRouter(prefix="/api/stats", tags=["统计"])
|
||||
|
||||
|
||||
@router.get("/dashboard")
|
||||
def get_dashboard(db: Session = Depends(get_db)):
|
||||
def get_dashboard(
|
||||
db: Session = Depends(get_db),
|
||||
_: dict = Depends(require_permission('device.view')),
|
||||
):
|
||||
"""仪表板统计:总体、城区、城郊、乡镇在线率"""
|
||||
# 每台设备最新状态子查询
|
||||
latest_subq = (
|
||||
@@ -92,7 +96,10 @@ def get_dashboard(db: Session = Depends(get_db)):
|
||||
|
||||
|
||||
@router.get("/summary")
|
||||
def get_summary(db: Session = Depends(get_db)):
|
||||
def get_summary(
|
||||
db: Session = Depends(get_db),
|
||||
_: dict = Depends(require_permission('device.view')),
|
||||
):
|
||||
"""获取统计摘要"""
|
||||
total = db.query(ONUDevice).count()
|
||||
latest_status = db.query(
|
||||
@@ -103,16 +110,139 @@ def get_summary(db: Session = Depends(get_db)):
|
||||
return {"total": total, "online": status_dict.get('online', 0), "offline": status_dict.get('offline', 0)}
|
||||
|
||||
|
||||
@router.get("/trend")
|
||||
def get_trend(days: int = 7, db: Session = Depends(get_db)):
|
||||
"""获取状态趋势数据"""
|
||||
start_date = datetime.utcnow() - timedelta(days=days)
|
||||
history = db.query(
|
||||
func.date(DeviceStatusHistory.checked_at).label('date'),
|
||||
func.sum(func.case((DeviceStatusHistory.status == 'online', 1), else_=0)).label('online'),
|
||||
func.sum(func.case((DeviceStatusHistory.status == 'offline', 1), else_=0)).label('offline')
|
||||
).filter(DeviceStatusHistory.checked_at >= start_date).group_by(
|
||||
func.date(DeviceStatusHistory.checked_at)
|
||||
).all()
|
||||
return [{"date": str(h.date), "online": h.online, "offline": h.offline} for h in history]
|
||||
@router.get("/by-region")
|
||||
def get_by_region(
|
||||
db: Session = Depends(get_db),
|
||||
_: dict = Depends(require_permission('device.view')),
|
||||
):
|
||||
"""各区域设备数量及在线率(用于饼图)"""
|
||||
latest_subq = (
|
||||
db.query(
|
||||
DeviceStatusHistory.onu_device_id,
|
||||
func.max(DeviceStatusHistory.checked_at).label("max_checked_at")
|
||||
)
|
||||
.group_by(DeviceStatusHistory.onu_device_id)
|
||||
.subquery()
|
||||
)
|
||||
latest_status_subq = (
|
||||
db.query(
|
||||
DeviceStatusHistory.onu_device_id,
|
||||
DeviceStatusHistory.status
|
||||
)
|
||||
.join(
|
||||
latest_subq,
|
||||
(DeviceStatusHistory.onu_device_id == latest_subq.c.onu_device_id) &
|
||||
(DeviceStatusHistory.checked_at == latest_subq.c.max_checked_at)
|
||||
)
|
||||
.subquery()
|
||||
)
|
||||
|
||||
rows = (
|
||||
db.query(
|
||||
ONUDevice.region,
|
||||
func.count().label("total"),
|
||||
func.sum(case((latest_status_subq.c.status == 'online', 1), else_=0)).label("online"),
|
||||
func.sum(case((latest_status_subq.c.status == 'offline', 1), else_=0)).label("offline"),
|
||||
)
|
||||
.outerjoin(latest_status_subq, ONUDevice.id == latest_status_subq.c.onu_device_id)
|
||||
.group_by(ONUDevice.region)
|
||||
.order_by(func.count().desc())
|
||||
.all()
|
||||
)
|
||||
|
||||
return [
|
||||
{
|
||||
"region": row.region or "未知",
|
||||
"total": int(row.total or 0),
|
||||
"online": int(row.online or 0),
|
||||
"offline": int(row.offline or 0),
|
||||
}
|
||||
for row in rows
|
||||
]
|
||||
|
||||
|
||||
@router.get("/trend")
|
||||
def get_trend(
|
||||
days: int = 7,
|
||||
db: Session = Depends(get_db),
|
||||
_: dict = Depends(require_permission('device.view')),
|
||||
):
|
||||
"""获取状态趋势数据(优先查快照表,不足时实时聚合)"""
|
||||
today = date.today()
|
||||
date_range = [(today - timedelta(days=i)).strftime('%Y-%m-%d') for i in range(days - 1, -1, -1)]
|
||||
|
||||
# 查快照表(不含今天,今天用实时数据)
|
||||
snapshots = (
|
||||
db.query(DeviceDailySnapshot)
|
||||
.filter(DeviceDailySnapshot.snapshot_date.in_(date_range[:-1]))
|
||||
.all()
|
||||
)
|
||||
snapshot_map = {s.snapshot_date: s for s in snapshots}
|
||||
|
||||
# 今天实时聚合
|
||||
today_str = today.strftime('%Y-%m-%d')
|
||||
start_of_today = datetime.combine(today, datetime.min.time())
|
||||
|
||||
daily_latest_subq = (
|
||||
db.query(
|
||||
DeviceStatusHistory.onu_device_id,
|
||||
func.max(DeviceStatusHistory.checked_at).label("max_checked_at"),
|
||||
)
|
||||
.filter(DeviceStatusHistory.checked_at >= start_of_today)
|
||||
.group_by(DeviceStatusHistory.onu_device_id)
|
||||
.subquery()
|
||||
)
|
||||
today_row = (
|
||||
db.query(
|
||||
func.sum(case((DeviceStatusHistory.status == 'online', 1), else_=0)).label("online"),
|
||||
func.sum(case((DeviceStatusHistory.status == 'offline', 1), else_=0)).label("offline"),
|
||||
)
|
||||
.join(
|
||||
daily_latest_subq,
|
||||
(DeviceStatusHistory.onu_device_id == daily_latest_subq.c.onu_device_id) &
|
||||
(DeviceStatusHistory.checked_at == daily_latest_subq.c.max_checked_at)
|
||||
)
|
||||
.one()
|
||||
)
|
||||
|
||||
result = []
|
||||
for d in date_range:
|
||||
if d == today_str:
|
||||
result.append({
|
||||
"date": d,
|
||||
"online": int(today_row.online or 0),
|
||||
"offline": int(today_row.offline or 0),
|
||||
})
|
||||
elif d in snapshot_map:
|
||||
s = snapshot_map[d]
|
||||
result.append({"date": d, "online": s.online, "offline": s.offline})
|
||||
else:
|
||||
# 快照缺失时实时聚合该天数据
|
||||
day = datetime.strptime(d, '%Y-%m-%d').date()
|
||||
day_start = datetime.combine(day, datetime.min.time())
|
||||
day_end = datetime.combine(day, datetime.max.time())
|
||||
subq = (
|
||||
db.query(
|
||||
DeviceStatusHistory.onu_device_id,
|
||||
func.max(DeviceStatusHistory.checked_at).label("max_checked_at"),
|
||||
)
|
||||
.filter(DeviceStatusHistory.checked_at.between(day_start, day_end))
|
||||
.group_by(DeviceStatusHistory.onu_device_id)
|
||||
.subquery()
|
||||
)
|
||||
row = (
|
||||
db.query(
|
||||
func.sum(case((DeviceStatusHistory.status == 'online', 1), else_=0)).label("online"),
|
||||
func.sum(case((DeviceStatusHistory.status == 'offline', 1), else_=0)).label("offline"),
|
||||
)
|
||||
.join(
|
||||
subq,
|
||||
(DeviceStatusHistory.onu_device_id == subq.c.onu_device_id) &
|
||||
(DeviceStatusHistory.checked_at == subq.c.max_checked_at)
|
||||
)
|
||||
.one()
|
||||
)
|
||||
result.append({"date": d, "online": int(row.online or 0), "offline": int(row.offline or 0)})
|
||||
|
||||
return result
|
||||
|
||||
|
||||
Reference in New Issue
Block a user