feat: 本体字段治理与风险规则模板执行器重构

- 新增本体字段注册表与字段治理审计脚本
- 重构风险规则模板执行器、DSL 验证与清单分类器
- 完善票据夹服务与差旅请求详情页交互
- 优化趋势图表与总览页数据展示
- 增强报销平台风险分级与模拟公司筛选
- 补充本体字段、风险规则生成与票据夹服务测试覆盖
This commit is contained in:
caoxiaozhu
2026-06-03 15:46:56 +08:00
parent e12b140508
commit 34457f9c3e
81 changed files with 4858 additions and 1073 deletions

View File

@@ -39,7 +39,8 @@ from app.services.agent_asset_spreadsheet_helpers import AgentAssetSpreadsheetHe
from app.services.agent_asset_timeline import AgentAssetTimelineMixin
from app.services.agent_foundation import AgentFoundationService
from app.services.audit import AuditLogService
from app.services.pagination import PageResult
from app.services.pagination import PageResult, normalize_page_params
from app.services.risk_rule_manifest_classifier import is_budget_risk_manifest
from app.services.risk_rule_score_backfill import backfill_missing_risk_rule_score
logger = get_logger("app.services.agent_assets")
@@ -77,6 +78,7 @@ class AgentAssetService(
assets = self.repository.list(
asset_type=asset_type, status=status, domain=domain, keyword=keyword
)
assets = self._filter_excluded_risk_assets(assets)
version_stats = self._collect_version_stats(assets)
return [self._serialize_list_item(asset, version_stats.get(asset.id)) for asset in assets]
@@ -93,17 +95,24 @@ class AgentAssetService(
self._ensure_ready()
if asset_type in {None, "", AgentAssetType.RULE.value}:
self.sync_platform_risk_rules_from_library()
result = self.repository.list_page(
assets = self.repository.list(
asset_type=asset_type,
status=status,
domain=domain,
keyword=keyword,
page=page,
page_size=page_size,
)
version_stats = self._collect_version_stats(result.items)
return result.map(
lambda asset: self._serialize_list_item(asset, version_stats.get(asset.id))
assets = self._filter_excluded_risk_assets(assets)
page_params = normalize_page_params(page, page_size)
paged_assets = assets[page_params.offset : page_params.offset + page_params.page_size]
version_stats = self._collect_version_stats(paged_assets)
return PageResult(
items=[
self._serialize_list_item(asset, version_stats.get(asset.id))
for asset in paged_assets
],
total=len(assets),
page=page_params.page,
page_size=page_params.page_size,
)
def get_asset(self, asset_id: str) -> AgentAssetRead | None:
@@ -151,6 +160,26 @@ class AgentAssetService(
else None,
)
@staticmethod
def _filter_excluded_risk_assets(assets: list[AgentAsset]) -> list[AgentAsset]:
return [asset for asset in assets if not AgentAssetService._is_excluded_budget_risk_asset(asset)]
@staticmethod
def _is_excluded_budget_risk_asset(asset: AgentAsset) -> bool:
if asset.asset_type != AgentAssetType.RULE.value:
return False
config_json = asset.config_json if isinstance(asset.config_json, dict) else {}
if str(config_json.get("detail_mode") or "").strip().lower() != "json_risk":
return False
manifest_like = {
**config_json,
"rule_code": str(asset.code or "").strip(),
"name": str(asset.name or "").strip(),
"description": str(asset.description or "").strip(),
"metadata": config_json,
}
return is_budget_risk_manifest(manifest_like)
def create_asset(
self,
payload: AgentAssetCreate,