- 新增BI模块(src/bi/),包含数据模型、服务和控制器 - 支持数据源管理、图表创建、看板配置 - 实现多图表类型:折线图、柱状图、饼图、散点图、面积图、仪表盘、表格 - 提供REST API(/bi/)和前端API(/bi-api/)接口 - 创建响应式前端界面,支持拖拽和实时数据展示 - 默认包含运营总览、设备管理、安全监控看板 - 支持与Superset和Metabase集成 🤖 Generated with [OpenClaw](https://github.com/robocomp/openclaw)
273 lines
10 KiB
Python
273 lines
10 KiB
Python
"""
|
|
BI控制器模块
|
|
提供REST API接口,支持自助BI看板和数据可视化
|
|
"""
|
|
from fastapi import APIRouter, HTTPException, Depends, Query, Path
|
|
from fastapi.responses import JSONResponse
|
|
from typing import List, Optional, Dict, Any
|
|
from datetime import datetime
|
|
from .services import BIService
|
|
from .models import ChartType, DataSourceType
|
|
|
|
# 创建路由器
|
|
router = APIRouter(prefix="/bi", tags=["BI"])
|
|
|
|
# 创建BI服务实例
|
|
bi_service = BIService()
|
|
|
|
@router.get("/")
|
|
async def get_bi_info():
|
|
"""获取BI系统信息"""
|
|
return {
|
|
"message": "Water Management System BI API",
|
|
"version": "1.0.0",
|
|
"endpoints": {
|
|
"charts": "/bi/charts",
|
|
"dashboards": "/bi/dashboards",
|
|
"data_sources": "/bi/data-sources",
|
|
"datasets": "/bi/datasets"
|
|
}
|
|
}
|
|
|
|
# 图表相关接口
|
|
@router.get("/charts", response_model=List[Dict[str, Any]])
|
|
async def get_all_charts():
|
|
"""获取所有图表"""
|
|
charts = bi_service.get_all_charts()
|
|
return [chart.to_dict() for chart in charts]
|
|
|
|
@router.get("/charts/{chart_id}", response_model=Dict[str, Any])
|
|
async def get_chart(chart_id: str = Path(..., description="图表ID")):
|
|
"""获取单个图表"""
|
|
chart = bi_service.get_chart(chart_id)
|
|
if not chart:
|
|
raise HTTPException(status_code=404, detail="Chart not found")
|
|
return chart.to_dict()
|
|
|
|
@router.post("/charts", response_model=Dict[str, Any])
|
|
async def create_chart(chart_data: Dict[str, Any]):
|
|
"""创建图表"""
|
|
try:
|
|
chart = bi_service.create_chart(chart_data)
|
|
return chart.to_dict()
|
|
except Exception as e:
|
|
raise HTTPException(status_code=400, detail=str(e))
|
|
|
|
@router.put("/charts/{chart_id}", response_model=Dict[str, Any])
|
|
async def update_chart(chart_id: str = Path(..., description="图表ID"), chart_data: Dict[str, Any] = None):
|
|
"""更新图表"""
|
|
if not chart_data:
|
|
raise HTTPException(status_code=400, detail="Chart data is required")
|
|
|
|
chart = bi_service.update_chart(chart_id, chart_data)
|
|
if not chart:
|
|
raise HTTPException(status_code=404, detail="Chart not found")
|
|
return chart.to_dict()
|
|
|
|
@router.delete("/charts/{chart_id}")
|
|
async def delete_chart(chart_id: str = Path(..., description="图表ID")):
|
|
"""删除图表"""
|
|
success = bi_service.delete_chart(chart_id)
|
|
if not success:
|
|
raise HTTPException(status_code=404, detail="Chart not found")
|
|
return {"message": "Chart deleted successfully"}
|
|
|
|
@router.get("/charts/{chart_id}/data", response_model=Dict[str, Any])
|
|
async def get_chart_data(chart_id: str = Path(..., description="图表ID")):
|
|
"""获取图表数据"""
|
|
data = bi_service.get_chart_data_api(chart_id)
|
|
if "error" in data:
|
|
raise HTTPException(status_code=404, detail=data["error"])
|
|
return data
|
|
|
|
# 看板相关接口
|
|
@router.get("/dashboards", response_model=List[Dict[str, Any]])
|
|
async def get_all_dashboards():
|
|
"""获取所有看板"""
|
|
dashboards = bi_service.get_all_dashboards()
|
|
return [dashboard.to_dict() for dashboard in dashboards]
|
|
|
|
@router.get("/dashboards/{dashboard_id}", response_model=Dict[str, Any])
|
|
async def get_dashboard(dashboard_id: str = Path(..., description="看板ID")):
|
|
"""获取单个看板"""
|
|
dashboard = bi_service.get_dashboard(dashboard_id)
|
|
if not dashboard:
|
|
raise HTTPException(status_code=404, detail="Dashboard not found")
|
|
return dashboard.to_dict()
|
|
|
|
@router.post("/dashboards", response_model=Dict[str, Any])
|
|
async def create_dashboard(dashboard_data: Dict[str, Any]):
|
|
"""创建看板"""
|
|
try:
|
|
dashboard = bi_service.create_dashboard(dashboard_data)
|
|
return dashboard.to_dict()
|
|
except Exception as e:
|
|
raise HTTPException(status_code=400, detail=str(e))
|
|
|
|
@router.put("/dashboards/{dashboard_id}", response_model=Dict[str, Any])
|
|
async def update_dashboard(dashboard_id: str = Path(..., description="看板ID"), dashboard_data: Dict[str, Any] = None):
|
|
"""更新看板"""
|
|
if not dashboard_data:
|
|
raise HTTPException(status_code=400, detail="Dashboard data is required")
|
|
|
|
dashboard = bi_service.update_dashboard(dashboard_id, dashboard_data)
|
|
if not dashboard:
|
|
raise HTTPException(status_code=404, detail="Dashboard not found")
|
|
return dashboard.to_dict()
|
|
|
|
@router.delete("/dashboards/{dashboard_id}")
|
|
async def delete_dashboard(dashboard_id: str = Path(..., description="看板ID")):
|
|
"""删除看板"""
|
|
success = bi_service.delete_dashboard(dashboard_id)
|
|
if not success:
|
|
raise HTTPException(status_code=404, detail="Dashboard not found")
|
|
return {"message": "Dashboard deleted successfully"}
|
|
|
|
@router.get("/dashboards/{dashboard_id}/data", response_model=Dict[str, Any])
|
|
async def get_dashboard_data(dashboard_id: str = Path(..., description="看板ID")):
|
|
"""获取看板数据"""
|
|
data = bi_service.get_dashboard_data_api(dashboard_id)
|
|
if "error" in data:
|
|
raise HTTPException(status_code=404, detail=data["error"])
|
|
return data
|
|
|
|
# 数据源相关接口
|
|
@router.get("/data-sources", response_model=List[Dict[str, Any]])
|
|
async def get_all_data_sources():
|
|
"""获取所有数据源"""
|
|
data_sources = bi_service.get_all_data_sources()
|
|
return [source.to_dict() for source in data_sources]
|
|
|
|
@router.get("/data-sources/{source_id}", response_model=Dict[str, Any])
|
|
async def get_data_source(source_id: str = Path(..., description="数据源ID")):
|
|
"""获取单个数据源"""
|
|
source = bi_service.get_data_source(source_id)
|
|
if not source:
|
|
raise HTTPException(status_code=404, detail="Data source not found")
|
|
return source.to_dict()
|
|
|
|
# 数据集相关接口
|
|
@router.get("/datasets", response_model=List[Dict[str, Any]])
|
|
async def get_all_datasets():
|
|
"""获取所有数据集"""
|
|
datasets = bi_service.get_all_datasets()
|
|
return [dataset.to_dict() for dataset in datasets]
|
|
|
|
@router.get("/datasets/{dataset_id}", response_model=Dict[str, Any])
|
|
async def get_dataset(dataset_id: str = Path(..., description="数据集ID")):
|
|
"""获取单个数据集"""
|
|
dataset = bi_service.get_dataset(dataset_id)
|
|
if not dataset:
|
|
raise HTTPException(status_code=404, detail="Dataset not found")
|
|
return dataset.to_dict()
|
|
|
|
# 搜索相关接口
|
|
@router.get("/search/charts")
|
|
async def search_charts(keyword: str = Query(..., description="搜索关键词")):
|
|
"""搜索图表"""
|
|
charts = bi_service.search_charts(keyword)
|
|
return [chart.to_dict() for chart in charts]
|
|
|
|
@router.get("/search/dashboards")
|
|
async def search_dashboards(keyword: str = Query(..., description="搜索关键词")):
|
|
"""搜索看板"""
|
|
dashboards = bi_service.search_dashboards(keyword)
|
|
return [dashboard.to_dict() for dashboard in dashboards]
|
|
|
|
# 标签相关接口
|
|
@router.get("/charts/tag/{tag}")
|
|
async def get_charts_by_tag(tag: str = Path(..., description="标签")):
|
|
"""根据标签获取图表"""
|
|
charts = bi_service.get_charts_by_tag(tag)
|
|
return [chart.to_dict() for chart in charts]
|
|
|
|
@router.get("/dashboards/tag/{tag}")
|
|
async def get_dashboards_by_tag(tag: str = Path(..., description="标签")):
|
|
"""根据标签获取看板"""
|
|
dashboards = bi_service.get_dashboards_by_tag(tag)
|
|
return [dashboard.to_dict() for dashboard in dashboards]
|
|
|
|
# 公开看板接口
|
|
@router.get("/public/dashboards")
|
|
async def get_public_dashboards():
|
|
"""获取公开看板"""
|
|
dashboards = bi_service.get_public_dashboards()
|
|
return [dashboard.to_dict() for dashboard in dashboards]
|
|
|
|
# 图表类型和枚举
|
|
@router.get("/types/chart-types")
|
|
async def get_chart_types():
|
|
"""获取支持的图表类型"""
|
|
return [{"value": ct.value, "label": ct.name} for ct in ChartType]
|
|
|
|
@router.get("/types/data-source-types")
|
|
async def get_data_source_types():
|
|
"""获取支持的数据源类型"""
|
|
return [{"value": dst.value, "label": dst.name} for dst in DataSourceType]
|
|
|
|
# 默认数据接口
|
|
@router.get("/default-charts")
|
|
async def get_default_charts():
|
|
"""获取默认图表"""
|
|
# 运营总览相关的图表
|
|
default_chart_ids = ["flow_trend", "device_status_distribution", "alert_level_stats", "system_performance"]
|
|
charts = [bi_service.get_chart(chart_id).to_dict() for chart_id in default_chart_ids if bi_service.get_chart(chart_id)]
|
|
return charts
|
|
|
|
@router.get("/default-dashboards")
|
|
async def get_default_dashboards():
|
|
"""获取默认看板"""
|
|
# 运营总览看板
|
|
default_dashboard_ids = ["operation_overview", "device_management", "security_monitoring"]
|
|
dashboards = [bi_service.get_dashboard(db_id).to_dict() for db_id in default_dashboard_ids if bi_service.get_dashboard(db_id)]
|
|
return dashboards
|
|
|
|
# Superset集成接口
|
|
@router.post("/integrations/superset")
|
|
async def setup_superset_integration(integration_data: Dict[str, Any]):
|
|
"""设置Superset集成"""
|
|
try:
|
|
integration = bi_service.setup_superset_integration(integration_data)
|
|
return integration.to_dict()
|
|
except Exception as e:
|
|
raise HTTPException(status_code=400, detail=str(e))
|
|
|
|
@router.get("/integrations/superset")
|
|
async def get_superset_integration():
|
|
"""获取Superset集成配置"""
|
|
if not bi_service.superset_integration:
|
|
raise HTTPException(status_code=404, detail="Superset integration not configured")
|
|
return bi_service.superset_integration.to_dict()
|
|
|
|
# Metabase集成接口
|
|
@router.post("/integrations/metabase")
|
|
async def setup_metabase_integration(integration_data: Dict[str, Any]):
|
|
"""设置Metabase集成"""
|
|
try:
|
|
integration = bi_service.setup_metabase_integration(integration_data)
|
|
return integration.to_dict()
|
|
except Exception as e:
|
|
raise HTTPException(status_code=400, detail=str(e))
|
|
|
|
@router.get("/integrations/metabase")
|
|
async def get_metabase_integration():
|
|
"""获取Metabase集成配置"""
|
|
if not bi_service.metabase_integration:
|
|
raise HTTPException(status_code=404, detail="Metabase integration not configured")
|
|
return bi_service.metabase_integration.to_dict()
|
|
|
|
# 统计信息接口
|
|
@router.get("/stats")
|
|
async def get_bi_stats():
|
|
"""获取BI系统统计信息"""
|
|
return {
|
|
"total_charts": len(bi_service.charts),
|
|
"total_dashboards": len(bi_service.dashboards),
|
|
"total_data_sources": len(bi_service.data_sources),
|
|
"total_datasets": len(bi_service.datasets),
|
|
"public_dashboards": len(bi_service.get_public_dashboards()),
|
|
"integrations": {
|
|
"superset_configured": bi_service.superset_integration is not None,
|
|
"metabase_configured": bi_service.metabase_integration is not None
|
|
}
|
|
} |