feat: 预算系统6项技术改进(告警归因/实际值自动归集/真零基/派生规则/告警路径统一/现金流分类)

P1-③ 告警归因: budget_deviation_alerts+alert_type/attribution/scenario_id, 归因引擎alert_attribution.py(子KPI/科目/量价差/趋势), deviation-check统一写归因+场景, GET /deviation-alerts/{id}/attribution详情(旧告警现场组装)
P1-④ 实际值自动归集: kpi_value_sources/kpi_value_collect_logs表+CRUD+试跑+覆盖率, 采集器kpi_value_collector.py(voucher_details/进销存/cash_plans按entity+period汇总, 幂等upsert不覆盖人工), crontab每日06:30
P2-① 真零基: budget_zero_based_items逐项论证表+generate, method-comparison有论证项逐项求和is_demo=false否则fallback
P2-② 派生规则: budget_derivation_rules配置表, apply-method优先读规则rule_source=configured
P2-⑤ 告警双路径合并: deviation_engine.build_deviation_alert统一函数, 方向列表配置化kpi_alert_higher_better+alert-direction接口
P2-⑥ 现金流分类: cash_plan_classify_rules规则表+cash_plan_unclassified待分类队列, sync-cash-plans未命中进队列不静默跳过
新增: GET /kpis/{kpi_id}/values + 前端kpiApi.values(归集标签页数据源), scenario_suggestions幂等seed(init_db)
测试: test_budget_tech_improve.py 15用例, 预算相关96 passed, 全量646 passed
This commit is contained in:
Hermes CI Fix
2026-08-28 18:03:47 +08:00
parent 3bc68fa1c6
commit 94aeb14e95
16 changed files with 3164 additions and 118 deletions
+34
View File
@@ -47,6 +47,8 @@ export const kpiApi = {
hierarchy: (params?: any) => api.get('/kpis/hierarchy', { params }),
// KPI-8: 因果链追踪
causalityChain: (id: number) => api.get(`/kpis/${id}/causality-chain`),
// KPI实际值列表(归集标签页)
values: (id: number, params?: any) => api.get(`/kpis/${id}/values`, { params }),
}
export const mapApi = {
@@ -208,6 +210,38 @@ export const budgetApi = {
deviationCheck: (data: any) => api.post('/budget/deviation-check', data),
listDeviationAlerts: (params?: any) => api.get('/budget/deviation-alerts', { params }),
updateDeviationAlert: (id: number, data: any) => api.put(`/budget/deviation-alerts/${id}`, data),
// P1-③ 告警归因
getAlertAttribution: (alertId: number) => api.get(`/budget/deviation-alerts/${alertId}/attribution`),
getAlertDirection: () => api.get('/budget/alert-direction'),
updateAlertDirection: (data: any) => api.put('/budget/alert-direction', data),
// P1-④ 实际值自动归集
valueSources: (params?: any) => api.get('/budget/value-sources', { params }),
createValueSource: (data: any) => api.post('/budget/value-sources', data),
updateValueSource: (id: number, data: any) => api.put(`/budget/value-sources/${id}`, data),
deleteValueSource: (id: number) => api.delete(`/budget/value-sources/${id}`),
testValueSource: (data: any) => api.post('/budget/value-sources/test', data),
runValueCollect: (data: any) => api.post('/budget/value-collect/run', data),
valueCollectLogs: (params?: any) => api.get('/budget/value-collect/logs', { params }),
valueSourceCoverage: () => api.get('/budget/value-sources/coverage'),
// P2-① 零基逐项论证
zeroBasedItems: (params?: any) => api.get('/budget/zero-based/items', { params }),
createZeroBasedItem: (data: any) => api.post('/budget/zero-based/items', data),
updateZeroBasedItem: (id: number, data: any) => api.put(`/budget/zero-based/items/${id}`, data),
deleteZeroBasedItem: (id: number) => api.delete(`/budget/zero-based/items/${id}`),
generateZeroBased: (data: any) => api.post('/budget/zero-based/generate', data),
// P2-② 派生规则
derivationRules: (params?: any) => api.get('/budget/derivation-rules', { params }),
createDerivationRule: (data: any) => api.post('/budget/derivation-rules', data),
updateDerivationRule: (id: number, data: any) => api.put(`/budget/derivation-rules/${id}`, data),
deleteDerivationRule: (id: number) => api.delete(`/budget/derivation-rules/${id}`),
// P2-⑥ 现金流分类规则 + 待分类队列
cashClassifyRules: () => api.get('/budget/cash-classify-rules'),
createCashClassifyRule: (data: any) => api.post('/budget/cash-classify-rules', data),
updateCashClassifyRule: (id: number, data: any) => api.put(`/budget/cash-classify-rules/${id}`, data),
deleteCashClassifyRule: (id: number) => api.delete(`/budget/cash-classify-rules/${id}`),
cashUnclassified: (params?: any) => api.get('/budget/cash-unclassified', { params }),
classifyCashUnclassified: (id: number, data: any) => api.post(`/budget/cash-unclassified/${id}/classify`, data),
ignoreCashUnclassified: (id: number) => api.post(`/budget/cash-unclassified/${id}/ignore`),
}
export const costApi = {