feat: 扩展风险规则体系、审批动态路由与预算中心列表化改造

- 新增 25+ 条风险规则(预算/报销/申请/通用类),完善风险规则模拟与反馈发布机制
- 引入费用审批动态路由、平台风险分级、预审与风险阶段管理
- 预算中心列表化改造,优化票据夹仪表盘与数字员工工作看板
- 新增 Hermes 风险线索收集器、Agent 链路追踪中心
- 扩展数字员工能力库(18 个领域 Skill)与交通费用自动预估
- 完善报销申请快速预览、权限控制与前端测试覆盖
This commit is contained in:
caoxiaozhu
2026-06-01 17:07:14 +08:00
parent 7989f3a159
commit 92444e7eae
285 changed files with 25075 additions and 2986 deletions

View File

@@ -12,19 +12,16 @@ SERVER_DIR = Path(__file__).resolve().parents[1]
RISK_RULE_DIR = SERVER_DIR / "rules" / "risk-rules"
BUDGET_EXPENSE_TYPES = (
BUDGET_EXPENSE_TYPES = ("all",)
SUPPORTED_DEMO_EXPENSE_TYPES = {
"all",
"travel",
"hotel",
"transport",
"meal",
"meeting",
"marketing",
"office",
"training",
"software",
"communication",
"welfare",
)
}
FIELD_LABELS = {
@@ -456,7 +453,7 @@ RULES: tuple[DemoRiskRule, ...] = (
"rule.expense.company_travel_expense_reimbursement",
"差旅住宿费标准",
("reimbursement",),
("travel", "hotel", "transport"),
("travel",),
"差旅金额达到大额阈值且缺少有效出差申请时触发。",
("差旅申请", "大额差旅", "未申请"),
"high",
@@ -688,6 +685,54 @@ RULES: tuple[DemoRiskRule, ...] = (
)
COMMUNICATION_RULES: tuple[DemoRiskRule, ...] = (
DemoRiskRule(
"risk.standard.communication_amount_over_policy",
"通信费金额超过月度标准",
"通信费、话费、流量费或宽带费超过公司月度标准,且缺少岗位必要性或专项审批说明。",
"费用标准",
"expense_standard_over_limit",
"expense.communication.policy",
"通信费报销规则",
("expense_application", "reimbursement"),
("communication",),
"通信费金额超过公司标准且没有岗位、项目或专项审批说明时触发。",
("通信费", "话费", "流量费", "宽带费", "超标准"),
"medium",
"manual_review",
68,
"medium",
field_keys=BASE_FIELDS + ("material.invoice_uploaded",),
),
DemoRiskRule(
"risk.standard.communication_account_mismatch",
"通信账户归属与报销人不一致",
"通信票据、运营商账单或号码归属信息与报销人不一致,且缺少代垫或统一缴费说明。",
"费用归属",
"expense_owner_mismatch",
"expense.communication.policy",
"通信费报销规则",
("reimbursement",),
("communication",),
"通信账户归属与报销人不一致且没有代垫、统一缴费或部门公共号码说明时触发。",
("号码归属", "账户不一致", "代垫", "统一缴费", "公共号码"),
"high",
"manual_review",
82,
"high",
requires_attachment=True,
field_keys=MATERIAL_FIELDS,
),
)
def _is_supported_demo_rule(rule: DemoRiskRule) -> bool:
return all(expense_type in SUPPORTED_DEMO_EXPENSE_TYPES for expense_type in rule.expense_types)
RULES = tuple(rule for rule in RULES if _is_supported_demo_rule(rule)) + COMMUNICATION_RULES
def main() -> None:
RISK_RULE_DIR.mkdir(parents=True, exist_ok=True)
for rule in RULES: