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:
@@ -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; }
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user