diff --git a/backend/app/api/dashboard.py b/backend/app/api/dashboard.py index 7211ee24..eddcc368 100644 --- a/backend/app/api/dashboard.py +++ b/backend/app/api/dashboard.py @@ -10,6 +10,7 @@ from app.deps import get_entity_id from app.models import KPIDefinition, KPIValue, KPIAlert, User, VoucherDetail from app.utils.cache import get as cache_get, set as cache_set from app.utils.voucher_guard import apply_voucher_guard +from app.utils.threshold_parser import eval_threshold # 指标方向(反向/正向)唯一权威源 = app.api.kpis.REVERSE_INDICATORS(2026-09-15 M2 准入2 收口)。 # 本文件原自带一份字面量副本,与 kpis.py 漂移后会与「能力评分」判定相反,故改为导入。 from app.api.kpis import REVERSE_INDICATORS @@ -529,17 +530,15 @@ def predict_kpis(db: Session = Depends(get_db), entity_id: int = Depends(get_ent predicted_value = a + b * n # 检查预测值是否触发阈值 + # 统一走 app.utils.threshold_parser(阈值语法单一事实源,2026-09-16 B1 修复): + # 原实现手工切操作符 + float(),只识别单条件标量表达式;生产库存在多条件 + # 表达式(如 `<=36|>=124`)/区间/负数 → float() 抛 ValueError → 端点 500。 + # eval_threshold 对非法/空表达式返回 False(不致命),并支持 A~B、C1|C2、负数。 alert_level = "none" - if k.threshold_red: - op = k.threshold_red[:2] if k.threshold_red[1] in "=<>" else k.threshold_red[0] - val = float(k.threshold_red.replace(op, "").strip()) - if (op in (">=", ">") and predicted_value >= val) or (op in ("<=", "<") and predicted_value <= val): - alert_level = "red" - if alert_level == "none" and k.threshold_yellow: - op = k.threshold_yellow[:2] if k.threshold_yellow[1] in "=<>" else k.threshold_yellow[0] - val = float(k.threshold_yellow.replace(op, "").strip()) - if (op in (">=", ">") and predicted_value >= val) or (op in ("<=", "<") and predicted_value <= val): - alert_level = "yellow" + if eval_threshold(predicted_value, k.threshold_red): + alert_level = "red" + elif eval_threshold(predicted_value, k.threshold_yellow): + alert_level = "yellow" predictions.append({ "kpi_id": k.id, diff --git a/frontend/src/views/ReportCenter.vue b/frontend/src/views/ReportCenter.vue index 3984a90f..9bfc1acc 100644 --- a/frontend/src/views/ReportCenter.vue +++ b/frontend/src/views/ReportCenter.vue @@ -396,7 +396,7 @@