diff --git a/backend/app/api/action_plans.py b/backend/app/api/action_plans.py index 486f1eb5..ccead096 100644 --- a/backend/app/api/action_plans.py +++ b/backend/app/api/action_plans.py @@ -143,3 +143,163 @@ def delete_plan(plan_id: int, db: Session = Depends(get_db)): db.delete(plan) db.commit() return {"message": "已删除"} + + +# ────────────────────────────────────────────── +# 功能5: COSO内控自检表 (CMA P1 - COSO五要素) +# ────────────────────────────────────────────── + +COSO_CHECKLIST_DATA = { + "hanke": { + "entity_name": "陕西酣客(白酒经销)", + "total_score": 46, + "max_score": 100, + "risk_level": "high", # high / medium / low + "risk_label": "高风险", + "elements": [ + { + "id": "control_environment", + "name": "控制环境", + "name_en": "Control Environment", + "score": 60, + "max_score": 100, + "status": "medium", + "items": [ + {"id": "ce_01", "text": "管理层重视内控", "passed": True, "detail": "✅ 任总亲自跟"}, + {"id": "ce_02", "text": "职责分离", "passed": True, "detail": "✅ 业务≠财务"}, + {"id": "ce_03", "text": "授权审批制度", "passed": False, "detail": "❌ 渠补无标准审批流程"}, + {"id": "ce_04", "text": "人事政策", "passed": False, "detail": "❌ 无定期轮岗"}, + ], + }, + { + "id": "risk_assessment", + "name": "风险评估", + "name_en": "Risk Assessment", + "score": 40, + "max_score": 100, + "status": "low", + "items": [ + {"id": "ra_01", "text": "风险识别机制", "passed": False, "detail": "❌ 没有系统风险清单"}, + {"id": "ra_02", "text": "风险应对预案", "passed": False, "detail": "❌ 现金断流无预案"}, + ], + }, + { + "id": "control_activities", + "name": "控制活动", + "name_en": "Control Activities", + "score": 30, + "max_score": 100, + "status": "low", + "items": [ + {"id": "ca_01", "text": "渠补审批流程", "passed": False, "detail": "❌ 口头谈,无记录"}, + {"id": "ca_02", "text": "费用审批流程", "passed": False, "detail": "❌ 超预算无拦截"}, + {"id": "ca_03", "text": "实物返利入账流程", "passed": False, "detail": "❌ 纯P&L不进系统"}, + ], + }, + { + "id": "information_communication", + "name": "信息与沟通", + "name_en": "Information & Communication", + "score": 70, + "max_score": 100, + "status": "medium", + "items": [ + {"id": "ic_01", "text": "财务报告及时性", "passed": True, "detail": "✅ 月度出表"}, + {"id": "ic_02", "text": "系统数据互通", "passed": False, "detail": "❌ 进销存≠财务账"}, + ], + }, + { + "id": "monitoring", + "name": "监控", + "name_en": "Monitoring", + "score": 30, + "max_score": 100, + "status": "low", + "items": [ + {"id": "mo_01", "text": "定期内审", "passed": False, "detail": "❌ 无"}, + {"id": "mo_02", "text": "异常追踪机制", "passed": False, "detail": "❌ 发现异常无跟踪"}, + ], + }, + ], + }, + "bohai": { + "entity_name": "陕西博海科技(IT服务)", + "total_score": 55, + "max_score": 100, + "risk_level": "medium", + "risk_label": "中风险", + "elements": [ + { + "id": "control_environment", + "name": "控制环境", + "name_en": "Control Environment", + "score": 70, + "max_score": 100, + "status": "medium", + "items": [ + {"id": "ce_01", "text": "管理层重视内控", "passed": True, "detail": "✅ 老板直接管"}, + {"id": "ce_02", "text": "职责分离", "passed": True, "detail": "✅ 业务≠财务≠技术"}, + {"id": "ce_03", "text": "授权审批制度", "passed": False, "detail": "❌ 部分项目无预算审批"}, + ], + }, + { + "id": "risk_assessment", + "name": "风险评估", + "name_en": "Risk Assessment", + "score": 50, + "max_score": 100, + "status": "low", + "items": [ + {"id": "ra_01", "text": "风险识别机制", "passed": False, "detail": "❌ 无正式风险清单"}, + {"id": "ra_02", "text": "风险应对预案", "passed": True, "detail": "✅ 重点项目有预案"}, + ], + }, + { + "id": "control_activities", + "name": "控制活动", + "name_en": "Control Activities", + "score": 50, + "max_score": 100, + "status": "low", + "items": [ + {"id": "ca_01", "text": "采购审批流程", "passed": True, "detail": "✅ 有标准流程"}, + {"id": "ca_02", "text": "项目交付流程", "passed": False, "detail": "❌ 验收流程不完善"}, + ], + }, + { + "id": "information_communication", + "name": "信息与沟通", + "name_en": "Information & Communication", + "score": 60, + "max_score": 100, + "status": "medium", + "items": [ + {"id": "ic_01", "text": "财务报告及时性", "passed": True, "detail": "✅ 月度出表"}, + {"id": "ic_02", "text": "项目沟通机制", "passed": False, "detail": "❌ 跨部门信息滞后"}, + ], + }, + { + "id": "monitoring", + "name": "监控", + "name_en": "Monitoring", + "score": 40, + "max_score": 100, + "status": "low", + "items": [ + {"id": "mo_01", "text": "定期内审", "passed": False, "detail": "❌ 无"}, + {"id": "mo_02", "text": "异常追踪机制", "passed": True, "detail": "✅ 项目延期有跟踪"}, + ], + }, + ], + }, +} + + +@router.get("/coso-checklist") +def get_coso_checklist(entity: str = "hanke"): + """COSO内控自检表 - CMA P1 COSO五要素""" + data = COSO_CHECKLIST_DATA.get(entity) + if not data: + data = COSO_CHECKLIST_DATA["hanke"] + data["entity_name"] = f"未知实体({entity}),默认返回酣客数据" + return data diff --git a/backend/app/api/alerts.py b/backend/app/api/alerts.py index 167310cf..8a4e1858 100644 --- a/backend/app/api/alerts.py +++ b/backend/app/api/alerts.py @@ -4,6 +4,9 @@ from sqlalchemy.orm import Session from app.database import get_db from app.auth_middleware import require_auth, require_role from app.models import KPIAlert, OperationLog +import logging + +logger = logging.getLogger("cma.alerts") router = APIRouter(prefix="/api/cma/alerts", tags=["预警"], dependencies=[Depends(require_role("ceo", "finance", "business", "it"))], @@ -28,3 +31,216 @@ def resolve_alert(alert_id: int, data: dict, db: Session = Depends(get_db)): from datetime import datetime; alert.resolved_at = datetime.now() db.commit() return {"message": "已处理", "assignee": alert.assignee} + +# ────────────────────────────────────────────── +# 功能4: 风险矩阵热力图 (CMA P2 - ERM框架、风险识别四象限) +# ────────────────────────────────────────────── + +RISK_MATRIX_DATA = { + "hanke": { + "entity_name": "陕西酣客(白酒经销)", + "quadrants": [ + { + "impact": "high", + "probability": "high", + "label": "高影响×高概率", + "risks": [ + { + "id": "risk_001", + "name": "流动性风险", + "impact_label": "高", + "probability_label": "高", + "detail": "现金2.2万 vs 短债350万 → 断流风险", + "impact_value": 90, + "probability_value": 85, + "type": "red", + "measures": ["催收大额应收", "协商短期借款续贷"], + "responsible": "任富海", + "deadline": "7月底", + }, + { + "id": "risk_002", + "name": "合规风险", + "impact_label": "高", + "probability_label": "高", + "detail": "欠税426万 · 折旧违规", + "impact_value": 95, + "probability_value": 80, + "type": "red", + "measures": ["补缴欠税计划", "重新梳理折旧政策"], + "responsible": "任富海", + "deadline": "8月底", + }, + ], + }, + { + "impact": "high", + "probability": "medium", + "label": "高影响×中概率", + "risks": [ + { + "id": "risk_003", + "name": "政策风险", + "impact_label": "高", + "probability_label": "中", + "detail": "白酒消费税调整可能导致成本上升15-20%", + "impact_value": 85, + "probability_value": 50, + "type": "orange", + "measures": ["关注政策动向", "预留税务缓冲资金"], + "responsible": "财务部", + "deadline": "持续关注", + }, + ], + }, + { + "impact": "medium", + "probability": "high", + "label": "中影响×高概率", + "risks": [ + { + "id": "risk_004", + "name": "运营风险", + "impact_label": "中", + "probability_label": "高", + "detail": "Model C 成本模型未落地,成本核算偏差", + "impact_value": 60, + "probability_value": 80, + "type": "yellow", + "measures": ["推动Model C落地", "建立成本标准化流程"], + "responsible": "财务部", + "deadline": "8月中", + }, + ], + }, + { + "impact": "medium", + "probability": "medium", + "label": "中影响×中概率", + "risks": [ + { + "id": "risk_005", + "name": "战略风险", + "impact_label": "中", + "probability_label": "中", + "detail": "酒类零交易,新业务方向不确定", + "impact_value": 55, + "probability_value": 55, + "type": "yellow", + "measures": ["制定新业务评估框架", "定期战略复盘"], + "responsible": "管理层", + "deadline": "9月底", + }, + ], + }, + { + "impact": "low", + "probability": "low", + "label": "低影响×低概率", + "risks": [ + { + "id": "risk_006", + "name": "市场风险", + "impact_label": "低", + "probability_label": "低", + "detail": "行业需求波动,但酣客已基本退出市场", + "impact_value": 25, + "probability_value": 20, + "type": "green", + "measures": ["定期监控行业数据"], + "responsible": "业务部", + "deadline": "每季度", + }, + { + "id": "risk_007", + "name": "人员风险", + "impact_label": "低", + "probability_label": "低", + "detail": "核心团队稳定,短期内无流失风险", + "impact_value": 20, + "probability_value": 15, + "type": "green", + "measures": ["保持团队激励", "关键岗位备份"], + "responsible": "人事部", + "deadline": "持续", + }, + ], + }, + ], + }, + "bohai": { + "entity_name": "陕西博海科技(IT服务)", + "quadrants": [ + { + "impact": "high", + "probability": "medium", + "label": "高影响×中概率", + "risks": [ + { + "id": "risk_b_001", + "name": "现金流风险", + "impact_label": "高", + "probability_label": "中", + "detail": "应收账款账期延长,现金流紧张", + "impact_value": 85, + "probability_value": 55, + "type": "orange", + "measures": ["加快应收催收", "建立信用管理制度"], + "responsible": "任富海", + "deadline": "7月底", + }, + ], + }, + { + "impact": "medium", + "probability": "high", + "label": "中影响×高概率", + "risks": [ + { + "id": "risk_b_002", + "name": "项目交付风险", + "impact_label": "中", + "probability_label": "高", + "detail": "多个项目并行,交付压力大", + "impact_value": 65, + "probability_value": 75, + "type": "yellow", + "measures": ["优化项目排期", "增加外包资源"], + "responsible": "项目部", + "deadline": "持续", + }, + ], + }, + { + "impact": "low", + "probability": "medium", + "label": "低影响×中概率", + "risks": [ + { + "id": "risk_b_003", + "name": "技术迭代风险", + "impact_label": "低", + "probability_label": "中", + "detail": "新技术跟踪不及时,可能落后", + "impact_value": 30, + "probability_value": 45, + "type": "green", + "measures": ["定期技术培训", "技术栈评估"], + "responsible": "技术部", + "deadline": "每季度", + }, + ], + }, + ], + }, +} + + +@router.get("/risk-matrix") +def get_risk_matrix(entity: str = Query("hanke", description="hanke/bohai")): + """风险矩阵热力图数据 - CMA P2 ERM四象限""" + data = RISK_MATRIX_DATA.get(entity) + if not data: + data = RISK_MATRIX_DATA["hanke"] + data["entity_name"] = f"未知实体({entity}),默认返回酣客数据" + return data diff --git a/backend/app/api/budget.py b/backend/app/api/budget.py index 68a99eb6..ab46345d 100644 --- a/backend/app/api/budget.py +++ b/backend/app/api/budget.py @@ -334,3 +334,103 @@ def get_deviation_report( "summary": summary, "items": items, } + + +# ────────────────────────────────────────────── +# 功能6: 预算方法三选一向导 (CMA P1 - 增量/零基/弹性) +# ────────────────────────────────────────────── + +@router.post("/method-comparison") +def budget_method_comparison(data: dict): + """ + 预算方法三选一对比计算 + 接收: { entity: "hanke", last_month_budget: 91, current_revenue: 122, ... } + 返回三种方法的计算结果 + """ + entity = data.get("entity", "hanke") + last_month_budget = data.get("last_month_budget", 91) # 上月预算(万) + current_revenue = data.get("current_revenue", 122) # 当前收入(万) + fixed_costs = data.get("fixed_costs", { + "rent": 15, # 房租(万) + "labor": 40, # 人工(万) + "entertainment": 16, # 招待费(万) + "misc": 12, # 杂项(万) + }) + variable_cost_rate = data.get("variable_cost_rate", 0.4862) # 变动成本率 + + # 1. 增量预算: 基于上月统一调整 + increment_rate = data.get("increment_rate", 0.05) # 5%增幅 + incremental_result = round(last_month_budget * (1 + increment_rate), 1) + incremental_detail = f"上月{last_month_budget}万 × (1+{increment_rate*100:.0f}%) = {incremental_result}万" + + # 2. 零基预算: 每项从零论证 + zbb_entertainment = round(fixed_costs.get("entertainment", 16) / 2, 1) # 砍半 + zbb_misc = round(fixed_costs.get("misc", 12) * 0.7, 1) # 压缩30% + zbb_total = round( + fixed_costs.get("rent", 15) + + fixed_costs.get("labor", 40) + + zbb_entertainment + + zbb_misc, + 1, + ) + zbb_savings = round(last_month_budget - zbb_total, 1) + zbb_detail = ( + f"房租{fixed_costs.get('rent', 15)}万(固定)+人工{fixed_costs.get('labor', 40)}万(砍不掉)" + f"+招待{zbb_entertainment}万(砍半)+杂项{zbb_misc}万(压缩)" + f"={zbb_total}万 ← 省{zbb_savings}万" + ) + + # 3. 弹性预算: 根据收入水平动态调整 + flexible_fixed = round(fixed_costs.get("rent", 15) + fixed_costs.get("labor", 40) * 0.5, 1) + flexible_variable = round(current_revenue * variable_cost_rate * 0.4, 1) + flexible_total = round(flexible_fixed + flexible_variable, 1) + flexible_variance = round(last_month_budget - flexible_total, 1) + flex_detail = ( + f"收入{current_revenue}万 → 对应费用预算 = {flexible_total}万" + f"(固定部分{flexible_fixed}万+变动部分{flexible_variable}万)" + f",实际{last_month_budget}万 → 差异{flexible_variance}万 → {'效率问题' if flexible_variance > 0 else '节省'}" + ) + + # 推荐方法 + recommended = "zero_based" + + return { + "entity": entity, + "entity_name": "陕西酣客(白酒经销)" if entity == "hanke" else "陕西博海科技(IT服务)", + "methods": [ + { + "id": "incremental", + "name": "增量预算", + "name_en": "Incremental Budgeting", + "result_value": incremental_result, + "detail": incremental_detail, + "pros": "简单快速", + "cons": "浪费持续", + "is_recommended": False, + }, + { + "id": "zero_based", + "name": "零基预算", + "name_en": "Zero-Based Budgeting (ZBB)", + "result_value": zbb_total, + "savings": zbb_savings, + "detail": zbb_detail, + "pros": "最合理", + "cons": "耗时", + "is_recommended": True, + }, + { + "id": "flexible", + "name": "弹性预算", + "name_en": "Flexible Budgeting", + "result_value": flexible_total, + "variance": flexible_variance, + "detail": flex_detail, + "pros": "动态响应", + "cons": "需要详细分类", + "is_recommended": False, + }, + ], + "recommended": recommended, + "recommended_name": "零基预算", + } diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts index 1008aa7c..1f45ec5c 100644 --- a/frontend/src/api/index.ts +++ b/frontend/src/api/index.ts @@ -84,6 +84,7 @@ export const dataApi = { export const alertApi = { list: (params?: any) => api.get('/alerts', { params }), resolve: (id: number, data: any) => api.post(`/alerts/${id}/resolve`, data), + riskMatrix: (params?: any) => api.get('/alerts/risk-matrix', { params }), } export const alertRulesApi = { @@ -120,6 +121,7 @@ export const actionPlanApi = { create: (data: any) => api.post('/action-plans', data), update: (id: number, data: any) => api.put(`/action-plans/${id}`, data), delete: (id: number) => api.delete(`/action-plans/${id}`), + cosoChecklist: (params?: any) => api.get('/action-plans/coso-checklist', { params }), } export const budgetApi = { @@ -129,6 +131,7 @@ export const budgetApi = { delete: (id: number) => api.delete(`/budget/plans/${id}`), autoDecompose: (data: any) => api.post('/budget/auto-decompose', data), deviationReport: (params?: any) => api.get('/budget/deviation-report', { params }), + methodComparison: (data: any) => api.post('/budget/method-comparison', data), } export const costApi = { diff --git a/frontend/src/views/ActionPlanLibrary.vue b/frontend/src/views/ActionPlanLibrary.vue index 3e0a7abb..9148693d 100644 --- a/frontend/src/views/ActionPlanLibrary.vue +++ b/frontend/src/views/ActionPlanLibrary.vue @@ -1,14 +1,21 @@ + + +