"""admin 首页三统计展示配置:列出三指标配置(+ 真实值预览)+ 改某指标(带审计 + 校验)。 每指标可独立选 real/manual/random。计算逻辑见 app/repositories/ops_stat.py。 权限:operator 可改(运营调门面数字),super 恒可。 """ from __future__ import annotations from typing import Annotated from fastapi import APIRouter, Depends, HTTPException, Request from app.admin.audit import write_audit from app.admin.deps import AdminDb, get_client_ip, get_current_admin, require_role from app.admin.schemas.ops_stat_config import ( OpsStatItemOut, OpsStatUpdateRequest, ) from app.models.admin import AdminUser from app.repositories import ops_stat router = APIRouter( prefix="/admin/api/dashboard-display", tags=["admin-dashboard-display"], dependencies=[Depends(get_current_admin)], ) @router.get("", response_model=list[OpsStatItemOut], summary="首页三统计配置 + 真实值预览") def list_display(db: AdminDb) -> list[OpsStatItemOut]: return [OpsStatItemOut(**item) for item in ops_stat.get_config(db)] @router.patch( "/{metric}", response_model=OpsStatItemOut, summary="改某指标展示配置(带审计)" ) def update_display( metric: str, body: OpsStatUpdateRequest, request: Request, admin: Annotated[AdminUser, Depends(require_role("operator"))], db: AdminDb, ) -> OpsStatItemOut: try: before, after = ops_stat.update_config( db, metric, mode=body.mode, manual_value=body.manual_value, random_mult_min=body.random_mult_min, random_mult_max=body.random_mult_max, random_tick_seconds=body.random_tick_seconds, random_anchor_minutes=body.random_anchor_minutes, random_kind=body.random_kind, random_step_min=body.random_step_min, random_step_max=body.random_step_max, real_offset=body.real_offset, allow_decrease=body.allow_decrease, random_initial=body.random_initial, apply_now=body.apply_now, admin_id=admin.id, commit=False, ) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) from e write_audit( db, admin, action="ops_stat_config.set", target_type="ops_stat_config", target_id=metric, detail={"before": before, "after": after}, ip=get_client_ip(request), commit=False, ) db.commit() item = next(it for it in ops_stat.get_config(db) if it["metric"] == metric) return OpsStatItemOut(**item)