diff --git a/app/park/routers.py b/app/park/routers.py index 1125428..52bab23 100644 --- a/app/park/routers.py +++ b/app/park/routers.py @@ -27,11 +27,15 @@ logger = logging.getLogger("dpm.api") def _resolve_tenant(authorization: str | None, tenant_id: str | None) -> str: - """解析目标园区:大屏 park-token > ?tenant_id= > 默认园区。""" - if authorization and authorization.startswith("Bearer "): - return parse_token(authorization.split(" ", 1)[1]) + """解析目标园区:?tenant_id=(admin 亮传)> 大屏 park-token > 默认园区。 + admin 携带平台 token,不应被当作 park-token 解析失败;故 tenant_id 优先。""" if tenant_id: return tenant_id + if authorization and authorization.startswith("Bearer "): + try: + return parse_token(authorization.split(" ", 1)[1]) + except HTTPException: + pass # 平台 token → 回退默认 return tenants.ensure_default_tenant() log = logging.getLogger("dpm.api") @@ -89,9 +93,9 @@ async def tenant_create(body: TenantBody): return {"ok": True, "tenant": t} -@router.put("/tenants/{tid}", summary="更新园区(名称/简介/账密/数据)") -async def tenant_update(tid: str, body: TenantBody): - patch = {k: v for k, v in body.model_dump().items() if v is not None} +@router.put("/tenants/{tid}", summary="更新园区(名称/简介/管理员账号/密码)") +async def tenant_update(tid: str, body: TenantPatch): + patch = {k: v for k, v in body.model_dump(exclude_none=True).items() if v is not None} t = tenants.update_tenant(tid, patch) if t is None: return JSONResponse({"ok": False, "error": "园区不存在"}, status_code=404) @@ -239,6 +243,34 @@ async def park_zones(authorization: str | None = Header(None), tenant_id: str | return get_engine(tid).snapshot().get("zones", []) +# ==================== 屏幕管理(园区端创建/管理大屏设备) ==================== + +class ScreenBody2(BaseModel): + device_id: str = "" + name: str = "" + role: str = "main" + location: str = "" + + +@router.get("/api/screens") +async def screens_list(authorization: str | None = Header(None), tenant_id: str | None = None): + tid = _resolve_tenant(authorization, tenant_id) + return tenants.list_screens(tid) + + +@router.post("/api/screens") +async def screens_create(body: ScreenBody2, authorization: str | None = Header(None), tenant_id: str | None = None): + tid = _resolve_tenant(authorization, tenant_id) + return tenants.create_screen(tid, body.model_dump()) + + +@router.delete("/api/screens/{sid}") +async def screens_delete(sid: str, authorization: str | None = Header(None), tenant_id: str | None = None): + tid = _resolve_tenant(authorization, tenant_id) + ok = tenants.delete_screen(tid, sid) + return {"ok": ok, "id": sid} + + # ==================== 入驻企业(租户 data.companies 主数据源) ==================== @router.get("/api/park/companies") @@ -482,8 +514,8 @@ async def display_register(body: RegisterBody, authorization: str | None = Heade @router.post("/api/display/command") -async def display_command_publish(body: DisplayCommandBody, authorization: str | None = Header(None)): - tid = require_tenant(authorization) +async def display_command_publish(body: DisplayCommandBody, authorization: str | None = Header(None), tenant_id: str | None = None): + tid = tenant_id or require_tenant(authorization) if body.action not in _VALID_DISPLAY_ACTIONS: return JSONResponse({"ok": False, "error": f"不支持的指令: {body.action}"}, status_code=400) cmd = hub.publish_command(body.action, body.params, body.screen_id or None, body.screen_role or None, tid)