feat(P1-1): KPI单值人工录入 — 新增POST /kpis/{id}/values + 前端录入弹窗
M02绩效管理闭环工具:客户/流程/学习层台账数据可直接在KPI详情录入 - 后端: 单值录入(期间+实际值), 同期间重复自动更新, 来源=manual/verified - 前端: 历史数据Tab新增'录入数据'按钮+弹窗(期间选择+数值输入) - 验证: C_SATISFACTION 2026-08录入85→更新88, 历史数据联动显示
This commit is contained in:
+51
-1
@@ -9,7 +9,7 @@ import json
|
||||
from app.database import get_db
|
||||
from app.deps import get_entity_id
|
||||
from app.auth_middleware import require_auth, require_role, filter_kpis_by_role, kpi_visible_dims
|
||||
from app.models import StrategicMap, MapObjective, KPIDefinition, KPIValue, KPIAlert, OperationLog, Entity, KPICausality, KPIHierarchy
|
||||
from app.models import StrategicMap, MapObjective, KPIDefinition, KPIValue, KPIAlert, OperationLog, Entity, KPICausality, KPIHierarchy, User
|
||||
from app.api.kpi_governance import validate_kpi_payload, kpi_issues_message
|
||||
|
||||
router = APIRouter(prefix="/api/cma/kpis", tags=["KPI字典"],
|
||||
@@ -475,6 +475,56 @@ def get_kpi_causality_chain(
|
||||
# 动态路由(必须在静态路由之后)
|
||||
# ============================================================
|
||||
|
||||
@router.post("/{kpi_id}/values")
|
||||
def create_kpi_value(
|
||||
kpi_id: int,
|
||||
data: dict,
|
||||
db: Session = Depends(get_db),
|
||||
entity_id: int = Depends(get_entity_id),
|
||||
current_user: User = Depends(require_auth),
|
||||
):
|
||||
"""录入KPI单值(人工数据录入,用于客户/流程/学习层台账数据)
|
||||
Body: {period: '2026-08', actual_value: 85}
|
||||
"""
|
||||
kpi = db.query(KPIDefinition).filter(KPIDefinition.id == kpi_id).first()
|
||||
if not kpi:
|
||||
raise HTTPException(404, "KPI不存在")
|
||||
if kpi.entity_id != entity_id:
|
||||
raise HTTPException(404, "KPI不存在")
|
||||
|
||||
period = data.get("period")
|
||||
actual_value = data.get("actual_value")
|
||||
if not period or actual_value is None:
|
||||
raise HTTPException(400, "缺少必要参数: period, actual_value")
|
||||
|
||||
# 同一期间重复录入 → 更新
|
||||
existing = db.query(KPIValue).filter(
|
||||
KPIValue.kpi_id == kpi_id,
|
||||
KPIValue.period == period,
|
||||
KPIValue.source_type == "manual",
|
||||
).first()
|
||||
if existing:
|
||||
existing.actual_value = float(actual_value)
|
||||
existing.data_status = "verified"
|
||||
existing.remark = f"人工录入(更新) by {current_user.username}"
|
||||
db.commit()
|
||||
return {"message": "已更新", "id": existing.id}
|
||||
|
||||
new_val = KPIValue(
|
||||
kpi_id=kpi_id,
|
||||
entity_id=entity_id,
|
||||
period=period,
|
||||
actual_value=float(actual_value),
|
||||
source_type="manual",
|
||||
source_batch=f"manual-{current_user.username}-{datetime.now().strftime('%Y%m%d')}",
|
||||
data_status="verified",
|
||||
remark=f"人工录入 by {current_user.username}",
|
||||
)
|
||||
db.add(new_val)
|
||||
db.commit()
|
||||
return {"message": "已录入", "id": new_val.id, "period": period, "actual_value": float(actual_value)}
|
||||
|
||||
|
||||
@router.get("/{kpi_id}")
|
||||
def get_kpi(kpi_id: int, db: Session = Depends(get_db), entity_id: int = Depends(get_entity_id)):
|
||||
kpi = db.query(KPIDefinition).filter(KPIDefinition.id == kpi_id).first()
|
||||
|
||||
Reference in New Issue
Block a user