Merge branch 'feature/p132_74-risk-engine' of https://gitee.glmszq.com/gsty/onederiv/trs into feature/p132_74-risk-engine

This commit is contained in:
ruisu
2026-07-13 15:48:21 +08:00
12 changed files with 69 additions and 19 deletions
@@ -16,6 +16,8 @@ namespace YLErp.DBModels
public string ConditionJson { get; set; }
/// <summary>规则执行表达式(C# 布尔表达式,引擎用 Roslyn 编译执行)</summary>
public string RuleExpr { get; set; }
/// <summary>规则说明</summary>
public string Description { get; set; }
/// <summary>规则状态</summary>
public RiskRuleStatus Status { get; set; } = RiskRuleStatus.Active;
/// <summary>版本号(乐观锁)</summary>
@@ -10,6 +10,8 @@ namespace YLErp.DBModels
{
/// <summary>关联规则 ID 列表(JSON 数组)</summary>
public string RuleIds { get; set; }
/// <summary>应用说明</summary>
public string Description { get; set; }
/// <summary>应用配置状态</summary>
public RiskRuleStatus Status { get; set; } = RiskRuleStatus.Active;
/// <summary>风控策略(预警/阻断)</summary>
@@ -6,6 +6,7 @@ CREATE TABLE `glms_risk_rule` (
`RuleText` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '规则文本',
`ConditionJson` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '条件JSON(结构化模式, RuleCondition数组)',
`RuleExpr` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '规则表达式(自由文本模式, 类C#表达式)',
`Description` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述',
`Status` tinyint NOT NULL DEFAULT 1 COMMENT '状态: 1=Active, 2=Disabled, 3=Deleted',
`Version` int NOT NULL DEFAULT 1 COMMENT '版本号(乐观锁)',
`OptId` int NULL DEFAULT NULL COMMENT '创建人Id',
@@ -21,6 +22,7 @@ CREATE TABLE `glms_risk_rule` (
CREATE TABLE `glms_risk_rule_application` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键Id',
`RuleIds` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '关联规则Id列表(逗号分隔)',
`Description` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述',
`Status` tinyint NOT NULL DEFAULT 1 COMMENT '状态: 1=Active, 2=Disabled, 3=Deleted',
`ControlStrategy` tinyint NOT NULL COMMENT '控制策略: 1=Block, 2=Approval, 3=Warning',
`TriggerPoints` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '触发时点(逗号分隔)',
@@ -9,6 +9,8 @@ namespace YLErp.Modules.RiskEngine.Dto
{
/// <summary>关联规则 ID 列表(JSON 数组)</summary>
public string RuleIds { get; set; }
/// <summary>应用说明</summary>
public string Description { get; set; }
/// <summary>风控策略</summary>
public RiskControlStrategy ControlStrategy { get; set; }
/// <summary>触发点列表(JSON 数组)</summary>
@@ -13,5 +13,7 @@ namespace YLErp.Modules.RiskEngine.Dto
public string ConditionJson { get; set; }
/// <summary>规则执行表达式</summary>
public string RuleExpr { get; set; }
/// <summary>规则说明</summary>
public string Description { get; set; }
}
}
@@ -12,6 +12,8 @@ namespace YLErp.Modules.RiskEngine.Dto
public long Id { get; set; }
/// <summary>关联规则 ID 列表(JSON 数组)</summary>
public string RuleIds { get; set; }
/// <summary>应用说明</summary>
public string Description { get; set; }
/// <summary>应用配置状态</summary>
public RiskRuleStatus Status { get; set; }
/// <summary>风控策略</summary>
@@ -12,6 +12,8 @@ namespace YLErp.Modules.RiskEngine.Dto
public long Id { get; set; }
/// <summary>关联规则 ID 列表(JSON 数组)</summary>
public string RuleIds { get; set; }
/// <summary>应用说明</summary>
public string Description { get; set; }
/// <summary>应用配置状态</summary>
public int Status { get; set; }
/// <summary>风控策略</summary>
@@ -19,6 +19,8 @@ namespace YLErp.Modules.RiskEngine.Dto
public string ConditionJson { get; set; }
/// <summary>规则执行表达式</summary>
public string RuleExpr { get; set; }
/// <summary>规则说明</summary>
public string Description { get; set; }
/// <summary>规则状态</summary>
public RiskRuleStatus Status { get; set; }
/// <summary>版本号</summary>
@@ -18,6 +18,8 @@ namespace YLErp.Modules.RiskEngine.Dto
public string ConditionJson { get; set; }
/// <summary>规则执行表达式</summary>
public string RuleExpr { get; set; }
/// <summary>规则说明</summary>
public string Description { get; set; }
/// <summary>规则状态</summary>
public RiskRuleStatus Status { get; set; }
/// <summary>版本号</summary>
@@ -9,6 +9,8 @@ namespace YLErp.Modules.RiskEngine.Dto
{
/// <summary>关联规则 ID 列表(JSON 数组)</summary>
public string RuleIds { get; set; }
/// <summary>应用说明</summary>
public string Description { get; set; }
/// <summary>风控策略</summary>
public RiskControlStrategy ControlStrategy { get; set; }
/// <summary>触发点列表(JSON 数组)</summary>
@@ -13,6 +13,8 @@ namespace YLErp.Modules.RiskEngine.Dto
public string ConditionJson { get; set; }
/// <summary>规则执行表达式</summary>
public string RuleExpr { get; set; }
/// <summary>规则说明</summary>
public string Description { get; set; }
/// <summary>版本号(乐观锁)</summary>
public int Version { get; set; }
}
+47 -19
View File
@@ -1,10 +1,8 @@
using BaseOUDAL;
using Newtonsoft.Json;
using Qdp.Foundation.Utilities;
using System.Linq.Expressions;
using YLErp.BLL;
using YLErp.DBModels;
using YLErp.Model;
using YLErp.Modules.RiskEngine.Dto;
/*
@@ -694,6 +692,7 @@ namespace YLErp.Modules.RiskEngine
RuleText = r.RuleText,
ConditionJson = r.ConditionJson,
RuleExpr = r.RuleExpr,
Description = r.Description,
Status = r.Status,
Version = r.Version,
OptName = r.OptName,
@@ -732,6 +731,7 @@ namespace YLErp.Modules.RiskEngine
RuleText = rule.RuleText,
ConditionJson = rule.ConditionJson,
RuleExpr = rule.RuleExpr,
Description = rule.Description,
Status = rule.Status,
Version = rule.Version,
OptName = rule.OptName,
@@ -749,12 +749,17 @@ namespace YLErp.Modules.RiskEngine
{
ValidateRuleParams(req.RuleName, req.ConditionJson, req.RuleExpr);
var compileResult = RuleCompiler.ValidateAndCompileFormula(null, req.RuleExpr);
if (!compileResult.Success)
throw new ServiceException($"规则表达式编译失败:{compileResult.ErrorMessage}");
var entity = new glms_risk_rule
{
RuleName = req.RuleName,
RuleText = req.RuleText,
ConditionJson = req.ConditionJson,
RuleExpr = req.RuleExpr,
Description = req.Description,
Status = RiskRuleStatus.Active,
Version = 1
};
@@ -784,7 +789,7 @@ namespace YLErp.Modules.RiskEngine
}
}
TryRefreshCache();
RiskEngineService.GetInstance().RefreshOneRuleCache(entity.id);
return GetRuleDetail(entity.id);
}
@@ -801,10 +806,15 @@ namespace YLErp.Modules.RiskEngine
ValidateRuleParams(req.RuleName, req.ConditionJson, req.RuleExpr);
var compileResult = RuleCompiler.ValidateAndCompileFormula(ruleId, req.RuleExpr);
if (!compileResult.Success)
throw new ServiceException($"规则表达式编译失败:{compileResult.ErrorMessage}");
rule.RuleName = req.RuleName;
rule.RuleText = req.RuleText;
rule.ConditionJson = req.ConditionJson;
rule.RuleExpr = req.RuleExpr;
rule.Description = req.Description;
rule.Version = rule.Version + 1;
rule.UpdateOptId = UserId;
rule.UpdateOptName = UserName;
@@ -813,7 +823,7 @@ namespace YLErp.Modules.RiskEngine
WriteAuditLog("RULE_UPDATE", "RULE", ruleId, req.RuleName, "修改规则");
DbContext.SaveChanges();
TryRefreshCache();
RiskEngineService.GetInstance().RefreshOneRuleCache(ruleId);
return GetRuleDetail(ruleId);
}
@@ -1074,6 +1084,7 @@ namespace YLErp.Modules.RiskEngine
{
Id = a.id,
RuleIds = a.RuleIds,
Description = a.Description,
Status = (int)a.Status,
ControlStrategy = a.ControlStrategy,
TriggerPoints = a.TriggerPoints,
@@ -1107,6 +1118,7 @@ namespace YLErp.Modules.RiskEngine
{
Id = app.id,
RuleIds = app.RuleIds,
Description = app.Description,
Status = app.Status,
ControlStrategy = app.ControlStrategy,
TriggerPoints = app.TriggerPoints,
@@ -1135,6 +1147,7 @@ namespace YLErp.Modules.RiskEngine
var entity = new glms_risk_rule_application
{
RuleIds = req.RuleIds,
Description = req.Description,
Status = RiskRuleStatus.Active,
ControlStrategy = req.ControlStrategy,
TriggerPoints = req.TriggerPoints,
@@ -1172,7 +1185,7 @@ namespace YLErp.Modules.RiskEngine
}
}
TryRefreshCache();
RiskEngineService.GetInstance().RefreshApplication();
return GetApplicationDetail(entity.id);
}
@@ -1203,6 +1216,7 @@ namespace YLErp.Modules.RiskEngine
if (!string.IsNullOrWhiteSpace(req.RuleIds))
app.RuleIds = req.RuleIds;
app.Description = req.Description;
app.ControlStrategy = req.ControlStrategy;
app.TriggerPoints = req.TriggerPoints;
app.ScopeAssetBookIds = req.ScopeAssetBookIds;
@@ -1219,7 +1233,7 @@ namespace YLErp.Modules.RiskEngine
$"修改应用配置:策略={GetStrategyName(req.ControlStrategy)}, 触发时点={MapTriggerPointsToChinese(req.TriggerPoints)}");
DbContext.SaveChanges();
TryRefreshCache();
RiskEngineService.GetInstance().RefreshApplication();
return GetApplicationDetail(applicationId);
}
@@ -1240,7 +1254,7 @@ namespace YLErp.Modules.RiskEngine
WriteAuditLog("APP_DELETE", "APPLICATION", applicationId, ResolveRuleNames(app.RuleIds), "删除应用配置");
DbContext.SaveChanges();
TryRefreshCache();
RiskEngineService.GetInstance().RefreshApplication();
}
/// <summary>
@@ -1262,7 +1276,7 @@ namespace YLErp.Modules.RiskEngine
WriteAuditLog("APP_ENABLE", "APPLICATION", applicationId, ResolveRuleNames(app.RuleIds), "启用应用配置");
DbContext.SaveChanges();
TryRefreshCache();
RiskEngineService.GetInstance().RefreshApplication();
}
/// <summary>
@@ -1282,7 +1296,7 @@ namespace YLErp.Modules.RiskEngine
WriteAuditLog("APP_DISABLE", "APPLICATION", applicationId, ResolveRuleNames(app.RuleIds), "停用应用配置");
DbContext.SaveChanges();
TryRefreshCache();
RiskEngineService.GetInstance().RefreshApplication();
}
/// <summary>
@@ -1313,7 +1327,7 @@ namespace YLErp.Modules.RiskEngine
}
DbContext.SaveChanges();
TryRefreshCache();
RiskEngineService.GetInstance().RefreshApplication();
return new BatchOperationResult
{
@@ -1346,7 +1360,7 @@ namespace YLErp.Modules.RiskEngine
}
DbContext.SaveChanges();
TryRefreshCache();
RiskEngineService.GetInstance().RefreshApplication();
return new BatchOperationResult
{
@@ -1534,14 +1548,24 @@ namespace YLErp.Modules.RiskEngine
if (variableExprChanged)
{
// 编译校验:变量表达式变更后,需验证所有级联更新的规则表达式可编译
var affectedRules = DbContext.glms_risk_rule
.Where(r => r.RuleExpr != null && r.RuleExpr.Contains(oldVariableExpr))
.ToList();
var compileTasks = affectedRules.Select(r =>
Task.Run(() => RuleCompiler.ValidateAndCompileFormula(
r.id, r.RuleExpr.Replace(oldVariableExpr, req.VariableExpr)))
);
var compileResults = Task.WhenAll(compileTasks).GetAwaiter().GetResult();
var failed = compileResults.FirstOrDefault(r => !r.Success);
if (failed is not null)
throw new ServiceException($"变量表达式变更导致规则编译失败:{failed.ErrorMessage}");
using (var transaction = DbContext.Database.BeginTransaction())
{
try
{
var affectedRules = DbContext.glms_risk_rule
.Where(r => r.RuleExpr != null && r.RuleExpr.Contains(oldVariableExpr))
.ToList();
foreach (var rule in affectedRules)
{
rule.RuleExpr = rule.RuleExpr.Replace(oldVariableExpr, req.VariableExpr);
@@ -1570,16 +1594,20 @@ namespace YLErp.Modules.RiskEngine
throw;
}
}
InvalidateVariableCache();
foreach (var rule in affectedRules)
{
RiskEngineService.GetInstance().RefreshOneRuleCache(rule.id);
}
}
else
{
WriteAuditLog("VAR_UPDATE", "VARIABLE", variableId, req.VariableName, $"修改变量:{variable.VariableName}");
DbContext.SaveChanges();
InvalidateVariableCache();
}
InvalidateVariableCache();
TryRefreshCache();
return GetVariableDetail(variableId);
}
@@ -1735,4 +1763,4 @@ namespace YLErp.Modules.RiskEngine
#endregion
}
}
}