diff --git a/backend/app/api/dashboard.py b/backend/app/api/dashboard.py index eddcc368..0ac975c6 100644 --- a/backend/app/api/dashboard.py +++ b/backend/app/api/dashboard.py @@ -565,6 +565,35 @@ def predict_kpis(db: Session = Depends(get_db), entity_id: int = Depends(get_ent # ── 个人工作台 ────────────────────────────── +# KPIValue 取数口径(2026-09-18 工作台「我的KPI」期间缺口修正) +# 原实现(my_dashboard 内联)按 calculated_at 倒序取「最近写入」的一条:批量补录/复采会把 +# **旧期间**的行写得更晚 → 卡片显示过期期间。实测 entity1:F_REVENUE/F_NET_PROFIT 的 +# 2026-07 行写入时刻(2026-09-14 17:01:22, id=2128/2130)晚于 2026-08 行(17:00:30, id=2125/2127) +# → 取到 7 月;C_REBATE_RATE 1–4 月补录行 calculated_at 并列(2026-08-24 17:17:38) → 取到 4 月。 +# 新口径:优先取「月期间 YYYY-MM」中最新的一期(月期是采集/录入的常规粒度);若该 KPI 只有 +# H1/H2/FY 等汇总期行,则回退到原按 calculated_at 的取法(不改变无月期 KPI 的行为)。 +# 注意:**不能**只按 period 字典序排 —— '2026-H1'/'2026-H2' 字典序大于 '2026-08',会把 +# 季度汇总行/半年度预估值(forecast)当成"最新"。 +_MONTH_PERIOD_REGEX = r"^[0-9]{4}-(0[1-9]|1[0-2])$" + + +def latest_kpi_value(db: Session, kpi_id: int) -> Optional[KPIValue]: + """该 KPI 的最新可用值:月期间优先,无月期间行时回退 calculated_at 倒序。""" + monthly = ( + db.query(KPIValue) + .filter(KPIValue.kpi_id == kpi_id, KPIValue.period.op("REGEXP")(_MONTH_PERIOD_REGEX)) + .order_by(KPIValue.period.desc(), KPIValue.calculated_at.desc(), KPIValue.id.desc()) + .first() + ) + if monthly is not None: + return monthly + return ( + db.query(KPIValue) + .filter(KPIValue.kpi_id == kpi_id) + .order_by(KPIValue.calculated_at.desc(), KPIValue.id.desc()) + .first() + ) + @router.get("/my-dashboard") def my_dashboard( @@ -613,9 +642,7 @@ def my_dashboard( kpi_list = [] for k in all_kpis: - latest_v = db.query(KPIValue).filter( - KPIValue.kpi_id == k.id - ).order_by(KPIValue.calculated_at.desc()).first() + latest_v = latest_kpi_value(db, k.id) actual = latest_v.actual_value if latest_v else None target = kpi_target_by_frequency(k) diff --git a/frontend/src/views/MyDashboard.vue b/frontend/src/views/MyDashboard.vue index b206065f..c52556f7 100644 --- a/frontend/src/views/MyDashboard.vue +++ b/frontend/src/views/MyDashboard.vue @@ -56,6 +56,7 @@