fix: CMA P0修复 - 评分引擎反向指标 + 清理重复KPI + 校准目标值

三项P0修复:
1. 评分引擎反向指标:新增REVERSE_INDICATORS列表和is_reverse参数,
   _calc_five_tier_score现在支持越低越好的指标评分
   (渠补率82.8%>75%从4分→2分)
2. 清理重复KPI:删除entity_id=2(博海)的56条重复KPI,
   从entity_id=1(酣客)重新克隆
3. 校准目标值:按审计报告更新酣客24项KPI目标值
   (F_REVENUE 4979→1200, F_NET_PROFIT 500→50等)
This commit is contained in:
Hermes CI Fix
2026-07-21 17:56:26 +08:00
parent 3852533129
commit 3db7bef025
+29 -12
View File
@@ -101,21 +101,38 @@ def get_kpi_categories(current_user = Depends(require_auth), db: Session = Depen
# KPI-5: 五档评分引擎(静态路由必须在动态/{kpi_id}之前) # KPI-5: 五档评分引擎(静态路由必须在动态/{kpi_id}之前)
# ============================================================ # ============================================================
def _calc_five_tier_score(current_value, target_value): REVERSE_INDICATORS = ['C_REBATE_RATE', 'P_BUG_RATE', 'P_REWORK_PCT', 'F_DEBT_RATIO',
"""五档评分:1-5分""" 'P_QUALITY_RATE', 'F_COST_RATIO', 'F_INTEREST_COVER', 'F_QUICK_RATIO']
def _calc_five_tier_score(current_value, target_value, is_reverse=False):
"""五档评分:1-5分(支持正反向指标)"""
if current_value is None or target_value is None or target_value == 0: if current_value is None or target_value is None or target_value == 0:
return None, "info" return None, "info"
ratio = current_value / target_value ratio = current_value / target_value
if ratio >= 1.2: if is_reverse:
return 5, "success" # 卓越 # 反向指标:实际值越低越好
elif ratio >= 1.0: if ratio <= 0.5:
return 4, "success" # 达标 return 5, "success" # 远低于目标→卓越
elif ratio >= 0.8: elif ratio <= 0.8:
return 3, "warning" # 预警 return 4, "success" # 低于目标→达标
elif ratio >= 0.5: elif ratio <= 1.0:
return 2, "danger" # 危险 return 3, "warning" # 接近目标→预警
elif ratio <= 1.2:
return 2, "danger" # 超过目标→危险
else:
return 1, "danger" # 远超目标→失效
else: else:
return 1, "danger" # 失效 if ratio >= 1.2:
return 5, "success" # 卓越
elif ratio >= 1.0:
return 4, "success" # 达标
elif ratio >= 0.8:
return 3, "warning" # 预警
elif ratio >= 0.5:
return 2, "danger" # 危险
else:
return 1, "danger" # 失效
@router.get("/score") @router.get("/score")
@@ -154,7 +171,7 @@ def get_kpi_score(
latest_val = val_query.order_by(KPIValue.period.desc()).first() latest_val = val_query.order_by(KPIValue.period.desc()).first()
current_val = latest_val.actual_value if latest_val else None current_val = latest_val.actual_value if latest_val else None
score, status = _calc_five_tier_score(current_val, k.target_value) score, status = _calc_five_tier_score(current_val, k.target_value, is_reverse=(k.kpi_code in REVERSE_INDICATORS))
kpi_scores.append({ kpi_scores.append({
"kpi_id": k.id, "kpi_id": k.id,