feat: 多租户实时切换 — 前端拦截器统一entity_id + 后端get_entity_id依赖 + dashboard 6端点支持租户过滤

- 前端: api/index.ts拦截器自动附加X-Entity-Id header + entity_id query参数
- 后端: 新增app/deps.py的get_entity_id公共依赖(query→header→默认1)
- dashboard.py: summary/kpis/finance-analysis/predict/my-kpis/my-dashboard全部支持entity_id
- 解决: 42个页面仅13个传entity_id导致切换企业后数据混乱
This commit is contained in:
Hermes CI Fix
2026-08-11 11:11:17 +08:00
parent dcc7e2194d
commit e959c40b1c
3 changed files with 52 additions and 8 deletions
+20 -8
View File
@@ -6,6 +6,7 @@ from datetime import datetime, timedelta
from typing import Optional
from app.database import get_db
from app.auth_middleware import require_auth, require_role
from app.deps import get_entity_id
from app.models import KPIDefinition, KPIValue, KPIAlert, User
from app.utils.cache import get as cache_get, set as cache_set
import json
@@ -52,15 +53,18 @@ def period_prefix(period_type: str):
return None
@router.get("/summary")
def get_dashboard_summary(role: str = Query("ceo"), period: str = Query("month"), db: Session = Depends(get_db)):
cache_key = f"summary:{role}:{period}"
def get_dashboard_summary(role: str = Query("ceo"), period: str = Query("month"),
db: Session = Depends(get_db), entity_id: int = Depends(get_entity_id)):
cache_key = f"summary:{role}:{period}:{entity_id}"
cached = cache_get("dashboard", cache_key)
if cached:
return cached
kpi_total = db.query(func.count(KPIDefinition.id)).filter(KPIDefinition.status == "active").scalar()
kpi_total = db.query(func.count(KPIDefinition.id)).filter(
KPIDefinition.status == "active", KPIDefinition.entity_id == entity_id).scalar()
alert_count = db.query(func.count(KPIAlert.id)).filter(KPIAlert.status == "pending").scalar()
dims = db.query(KPIDefinition.dimension, func.count(KPIDefinition.id)).filter(
KPIDefinition.status == "active").group_by(KPIDefinition.dimension).all()
KPIDefinition.status == "active", KPIDefinition.entity_id == entity_id
).group_by(KPIDefinition.dimension).all()
# 读取最近一次同步状态(从日志文件最后一行)
sync_status = {"last_sync": None, "status": "unknown", "detail": ""}
@@ -94,11 +98,14 @@ def get_dashboard_summary(role: str = Query("ceo"), period: str = Query("month")
@router.get("/kpis")
def get_dashboard_kpis(role: str = Query("ceo"), period: str = Query("month"),
start_date: str = Query(None), end_date: str = Query(None),
db: Session = Depends(get_db)):
db: Session = Depends(get_db), entity_id: int = Depends(get_entity_id)):
start, end = parse_period(period, start_date, end_date)
period_str = start.strftime("%Y-%m")
kpis = db.query(KPIDefinition).filter(KPIDefinition.status == "active").all()
kpis = db.query(KPIDefinition).filter(
KPIDefinition.status == "active",
KPIDefinition.entity_id == entity_id
).all()
result = []
for k in kpis:
@@ -213,6 +220,7 @@ def get_finance_analysis(
current_user: User = Depends(require_auth),
period: str = Query("month"),
db: Session = Depends(get_db),
entity_id: int = Depends(get_entity_id),
):
"""财务工作台分析数据"""
period_str = datetime.now().strftime("%Y-%m")
@@ -220,6 +228,7 @@ def get_finance_analysis(
finance_kpis = db.query(KPIDefinition).filter(
KPIDefinition.status == "active",
KPIDefinition.dimension == "finance",
KPIDefinition.entity_id == entity_id,
).all()
kpi_data = []
@@ -269,7 +278,7 @@ def get_finance_analysis(
@router.get("/predict")
def predict_kpis(db: Session = Depends(get_db)):
def predict_kpis(db: Session = Depends(get_db), entity_id: int = Depends(get_entity_id)):
"""基于历史趋势预测下月KPI值(简单线性回归)"""
from datetime import datetime, timedelta
@@ -281,7 +290,10 @@ def predict_kpis(db: Session = Depends(get_db)):
next_year += 1
next_period = f"{next_year}-{next_month:02d}"
kpis = db.query(KPIDefinition).filter(KPIDefinition.status == "active").all()
kpis = db.query(KPIDefinition).filter(
KPIDefinition.status == "active",
KPIDefinition.entity_id == entity_id
).all()
predictions = []
for k in kpis: