diff --git a/Framework/YLErp.Core/DBModels/glms_risk_rule_application.cs b/Framework/YLErp.Core/DBModels/glms_risk_rule_application.cs
index aa5dbb6a..a1d577ac 100644
--- a/Framework/YLErp.Core/DBModels/glms_risk_rule_application.cs
+++ b/Framework/YLErp.Core/DBModels/glms_risk_rule_application.cs
@@ -13,7 +13,7 @@ namespace YLErp.DBModels
public string ScopeClientIds { get; set; }
public string ScopeUnderlyingTypes { get; set; }
public string ScopeTradeTypes { get; set; }
- public bool ScopeIsGlobal { get; set; }
+ public int ScopeIsGlobal { get; set; }
public int Version { get; set; } = 1;
public int? UpdateOptId { get; set; }
public string UpdateOptName { get; set; }
diff --git a/Framework/YLErp.Resources/DbUpdate/Ver-5.6.0/seed_menu_risk_alert.sql b/Framework/YLErp.Resources/DbUpdate/Ver-5.6.0/seed_menu_risk_alert.sql
new file mode 100644
index 00000000..68a57b0d
--- /dev/null
+++ b/Framework/YLErp.Resources/DbUpdate/Ver-5.6.0/seed_menu_risk_alert.sql
@@ -0,0 +1,50 @@
+-- ============================================================
+-- 异常交易监控页面 - 操作权限(按钮)数据
+-- 依赖:异常交易监控菜单 id=1077 (type=1) 需先插入
+-- 对应 FunctionRight.xml 风险控制下风控相关操作权限(共16个按钮)
+-- type: 0=目录 1=菜单 2=按钮
+-- ============================================================
+
+-- ----------------------------
+-- 1. sys_menu 页面+按钮(type=1,2)
+-- ----------------------------
+INSERT INTO `yltrs_admin`.`sys_menu` (`id`, `pid`, `pids`, `name`, `code`, `type`, `icon`, `router`, `component`, `permission`, `application`, `open_type`, `visible`, `link`, `redirect`, `weight`, `sort`, `remark`, `status`, `create_time`, `create_user`, `update_time`, `update_user`) VALUES
+(1077, 99, NULL, '异常交易监控', NULL, 1, NULL, NULL, NULL, '异常交易监控', NULL, NULL, NULL, NULL, NULL, NULL, 0, '', 0, NULL, NULL, NULL, NULL),
+(1078, 1077, NULL, '风控规则查看', NULL, 2, NULL, NULL, NULL, '风控规则查看', NULL, NULL, NULL, NULL, NULL, NULL, 1, '', 0, NULL, NULL, NULL, NULL),
+(1079, 1077, NULL, '风控规则新增', NULL, 2, NULL, NULL, NULL, '风控规则新增', NULL, NULL, NULL, NULL, NULL, NULL, 2, '', 0, NULL, NULL, NULL, NULL),
+(1080, 1077, NULL, '风控规则编辑', NULL, 2, NULL, NULL, NULL, '风控规则编辑', NULL, NULL, NULL, NULL, NULL, NULL, 3, '', 0, NULL, NULL, NULL, NULL),
+(1081, 1077, NULL, '风控规则删除', NULL, 2, NULL, NULL, NULL, '风控规则删除', NULL, NULL, NULL, NULL, NULL, NULL, 4, '', 0, NULL, NULL, NULL, NULL),
+(1082, 1077, NULL, '风控规则启停', NULL, 2, NULL, NULL, NULL, '风控规则启停', NULL, NULL, NULL, NULL, NULL, NULL, 5, '', 0, NULL, NULL, NULL, NULL),
+(1083, 1077, NULL, '风控应用查看', NULL, 2, NULL, NULL, NULL, '风控应用查看', NULL, NULL, NULL, NULL, NULL, NULL, 6, '', 0, NULL, NULL, NULL, NULL),
+(1084, 1077, NULL, '风控应用新增', NULL, 2, NULL, NULL, NULL, '风控应用新增', NULL, NULL, NULL, NULL, NULL, NULL, 7, '', 0, NULL, NULL, NULL, NULL),
+(1085, 1077, NULL, '风控应用编辑', NULL, 2, NULL, NULL, NULL, '风控应用编辑', NULL, NULL, NULL, NULL, NULL, NULL, 8, '', 0, NULL, NULL, NULL, NULL),
+(1086, 1077, NULL, '风控应用删除', NULL, 2, NULL, NULL, NULL, '风控应用删除', NULL, NULL, NULL, NULL, NULL, NULL, 9, '', 0, NULL, NULL, NULL, NULL),
+(1087, 1077, NULL, '风控应用启停', NULL, 2, NULL, NULL, NULL, '风控应用启停', NULL, NULL, NULL, NULL, NULL, NULL, 10, '', 0, NULL, NULL, NULL, NULL),
+(1088, 1077, NULL, '风控变量查看', NULL, 2, NULL, NULL, NULL, '风控变量查看', NULL, NULL, NULL, NULL, NULL, NULL, 11, '', 0, NULL, NULL, NULL, NULL),
+(1089, 1077, NULL, '风控变量新增', NULL, 2, NULL, NULL, NULL, '风控变量新增', NULL, NULL, NULL, NULL, NULL, NULL, 12, '', 0, NULL, NULL, NULL, NULL),
+(1090, 1077, NULL, '风控变量编辑', NULL, 2, NULL, NULL, NULL, '风控变量编辑', NULL, NULL, NULL, NULL, NULL, NULL, 13, '', 0, NULL, NULL, NULL, NULL),
+(1091, 1077, NULL, '风控变量删除', NULL, 2, NULL, NULL, NULL, '风控变量删除', NULL, NULL, NULL, NULL, NULL, NULL, 14, '', 0, NULL, NULL, NULL, NULL),
+(1092, 1077, NULL, '风控日志查看', NULL, 2, NULL, NULL, NULL, '风控日志查看', NULL, NULL, NULL, NULL, NULL, NULL, 15, '', 0, NULL, NULL, NULL, NULL),
+(1093, 1077, NULL, '风控日志导出', NULL, 2, NULL, NULL, NULL, '风控日志导出', NULL, NULL, NULL, NULL, NULL, NULL, 16, '', 0, NULL, NULL, NULL, NULL);
+
+-- ----------------------------
+-- 2. sys_role_menu 角色1的按钮权限
+-- ----------------------------
+INSERT INTO `yltrs_admin`.`sys_role_menu` (`id`, `role_id`, `menu_id`) VALUES
+(1097, 1, 1077),
+(1098, 1, 1078),
+(1099, 1, 1079),
+(1100, 1, 1080),
+(1101, 1, 1081),
+(1102, 1, 1082),
+(1103, 1, 1083),
+(1104, 1, 1084),
+(1105, 1, 1085),
+(1106, 1, 1086),
+(1107, 1, 1087),
+(1108, 1, 1088),
+(1109, 1, 1089),
+(1110, 1, 1090),
+(1111, 1, 1091),
+(1112, 1, 1092),
+(1113, 1, 1093);
diff --git a/Framework/YLErp.Resources/DbUpdate/Ver-5.6.0/seed_rules.sql b/Framework/YLErp.Resources/DbUpdate/Ver-5.6.0/seed_rules.sql
index 45a17cb9..9751a1d9 100644
--- a/Framework/YLErp.Resources/DbUpdate/Ver-5.6.0/seed_rules.sql
+++ b/Framework/YLErp.Resources/DbUpdate/Ver-5.6.0/seed_rules.sql
@@ -50,7 +50,7 @@ INSERT INTO `glms_risk_rule` (`RuleName`, `RuleText`, `ConditionJson`, `RuleExpr
'挂钩标的到期日早于合约到期日时禁止交易',
JSON_ARRAY(JSON_OBJECT(
'VariableId', 22,
- 'Operator', '<', 'ThresholdType', 'Variable',
+ 'Operator', '早于', 'ThresholdType', 'Variable',
'ThresholdVariableId', 3
)),
'market.UnderlyingMaturityDate < trade.ExerciseDate',
@@ -87,7 +87,8 @@ INSERT INTO `glms_risk_rule` (`RuleName`, `RuleText`, `ConditionJson`, `RuleExpr
'保证金利率不在配置区间内(默认2%~5%)时触发审批',
JSON_ARRAY(JSON_OBJECT(
'VariableId', 12,
- 'Operator', '不介于', 'ThresholdType', 'Fixed', 'Value', JSON_ARRAY(2, 5)
+ 'Operator', '不介于', 'ThresholdType', 'Fixed', 'Value', JSON_ARRAY(2, 5),
+ 'IncludeLowerBound', true, 'IncludeUpperBound', true
)),
'!(client_marginrate.InitMarginRebateRate >= 2 && client_marginrate.InitMarginRebateRate <= 5)',
1, 1, 0, 'SYSTEM', NOW());
@@ -112,7 +113,7 @@ INSERT INTO `glms_risk_rule` (`RuleName`, `RuleText`, `ConditionJson`, `RuleExpr
'合约起息日早于当前日期时触发审批',
JSON_ARRAY(JSON_OBJECT(
'VariableId', 2,
- 'Operator', '<', 'ThresholdType', 'Variable',
+ 'Operator', '早于', 'ThresholdType', 'Variable',
'ThresholdVariableId', 21
)),
'trade.StartDate < sys.CurrentDate',
diff --git a/YLErpDAL/Modules/RiskEngine/Compile/RuleCompiler.cs b/YLErpDAL/Modules/RiskEngine/Compile/RuleCompiler.cs
index aed0f953..cd3db839 100644
--- a/YLErpDAL/Modules/RiskEngine/Compile/RuleCompiler.cs
+++ b/YLErpDAL/Modules/RiskEngine/Compile/RuleCompiler.cs
@@ -189,6 +189,29 @@ namespace YLErp.Modules.RiskEngine
};
}
+ ///
+ /// 将操作符统一为 C# 操作符
+ ///
+ private static string FormatOperator(string op)
+ {
+ return op?.Trim() switch
+ {
+ // 数值型 C# 符号
+ "=" or "==" => "==",
+ "!=" or "≠" => "!=",
+ ">" => ">",
+ "<" => "<",
+ ">=" => ">=",
+ "<=" => "<=",
+ // 日期型中文语义 → C# 符号
+ "早于" => "<",
+ "晚于" => ">",
+ "等于" => "==",
+ "不早于" => ">=",
+ "不晚于" => "<=",
+ _ => throw new ArgumentException($"不支持的操作符:{op}")
+ };
+ }
public static BuildMemberAccessResult Fail(string errorMessage)
{
return new BuildMemberAccessResult
diff --git a/YLErpDAL/Modules/RiskEngine/Dto/CreateRiskApplicationReq.cs b/YLErpDAL/Modules/RiskEngine/Dto/CreateRiskApplicationReq.cs
index f50d4f36..65e939c4 100644
--- a/YLErpDAL/Modules/RiskEngine/Dto/CreateRiskApplicationReq.cs
+++ b/YLErpDAL/Modules/RiskEngine/Dto/CreateRiskApplicationReq.cs
@@ -11,6 +11,6 @@ namespace YLErp.Modules.RiskEngine.Dto
public string ScopeClientIds { get; set; }
public string ScopeUnderlyingTypes { get; set; }
public string ScopeTradeTypes { get; set; }
- public bool ScopeIsGlobal { get; set; }
+ public int ScopeIsGlobal { get; set; }
}
}
diff --git a/YLErpDAL/Modules/RiskEngine/Dto/QueryRiskApplicationReq.cs b/YLErpDAL/Modules/RiskEngine/Dto/QueryRiskApplicationReq.cs
index bd494ed8..eec45ca7 100644
--- a/YLErpDAL/Modules/RiskEngine/Dto/QueryRiskApplicationReq.cs
+++ b/YLErpDAL/Modules/RiskEngine/Dto/QueryRiskApplicationReq.cs
@@ -9,5 +9,9 @@ namespace YLErp.Modules.RiskEngine.Dto
public RiskRuleStatus? Status { get; set; }
public RiskControlStrategy? Strategy { get; set; }
public string TriggerPoint { get; set; }
+ public string ScopeClientIds { get; set; }
+ public string ScopeUnderlyingTypes { get; set; }
+ public string ScopeTradeTypes { get; set; }
+ public string ScopeAssetBookIds { get; set; }
}
}
diff --git a/YLErpDAL/Modules/RiskEngine/Dto/QueryRiskAuditLogReq.cs b/YLErpDAL/Modules/RiskEngine/Dto/QueryRiskAuditLogReq.cs
index 690712fa..6e77c983 100644
--- a/YLErpDAL/Modules/RiskEngine/Dto/QueryRiskAuditLogReq.cs
+++ b/YLErpDAL/Modules/RiskEngine/Dto/QueryRiskAuditLogReq.cs
@@ -6,7 +6,10 @@ namespace YLErp.Modules.RiskEngine.Dto
public class QueryRiskAuditLogReq : BaseSearchReq
{
public string OperationType { get; set; }
+ public string OperationTypes { get; set; }
public string TargetType { get; set; }
+ public string TargetName { get; set; }
+ public string OptName { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public string Keyword { get; set; }
diff --git a/YLErpDAL/Modules/RiskEngine/Dto/QueryRiskVariableReq.cs b/YLErpDAL/Modules/RiskEngine/Dto/QueryRiskVariableReq.cs
index 639d9b3d..9b8f39bd 100644
--- a/YLErpDAL/Modules/RiskEngine/Dto/QueryRiskVariableReq.cs
+++ b/YLErpDAL/Modules/RiskEngine/Dto/QueryRiskVariableReq.cs
@@ -6,6 +6,7 @@ namespace YLErp.Modules.RiskEngine.Dto
public class QueryRiskVariableReq : BaseSearchReq
{
public RiskVariableCategory? Category { get; set; }
+ public RiskVariableDataType? DataType { get; set; }
public string VariableName { get; set; }
}
}
diff --git a/YLErpDAL/Modules/RiskEngine/Dto/RiskApplicationDetail.cs b/YLErpDAL/Modules/RiskEngine/Dto/RiskApplicationDetail.cs
index 52824a0d..cb76b20c 100644
--- a/YLErpDAL/Modules/RiskEngine/Dto/RiskApplicationDetail.cs
+++ b/YLErpDAL/Modules/RiskEngine/Dto/RiskApplicationDetail.cs
@@ -14,7 +14,7 @@ namespace YLErp.Modules.RiskEngine.Dto
public string ScopeClientIds { get; set; }
public string ScopeUnderlyingTypes { get; set; }
public string ScopeTradeTypes { get; set; }
- public bool ScopeIsGlobal { get; set; }
+ public int ScopeIsGlobal { get; set; }
public int Version { get; set; }
public string OptName { get; set; }
public DateTime OptDate { get; set; }
diff --git a/YLErpDAL/Modules/RiskEngine/Dto/RiskApplicationListItem.cs b/YLErpDAL/Modules/RiskEngine/Dto/RiskApplicationListItem.cs
index fcaaf7df..466b1d94 100644
--- a/YLErpDAL/Modules/RiskEngine/Dto/RiskApplicationListItem.cs
+++ b/YLErpDAL/Modules/RiskEngine/Dto/RiskApplicationListItem.cs
@@ -7,14 +7,14 @@ namespace YLErp.Modules.RiskEngine.Dto
{
public long Id { get; set; }
public string RuleIds { get; set; }
- public RiskRuleStatus Status { get; set; }
+ public int Status { get; set; }
public RiskControlStrategy ControlStrategy { get; set; }
public string TriggerPoints { get; set; }
public string ScopeAssetBookIds { get; set; }
public string ScopeClientIds { get; set; }
public string ScopeUnderlyingTypes { get; set; }
public string ScopeTradeTypes { get; set; }
- public bool ScopeIsGlobal { get; set; }
+ public int ScopeIsGlobal { get; set; }
public int Version { get; set; }
public string OptName { get; set; }
public DateTime OptDate { get; set; }
diff --git a/YLErpDAL/Modules/RiskEngine/Dto/RuleCondition.cs b/YLErpDAL/Modules/RiskEngine/Dto/RuleCondition.cs
index 81facae9..d1e459ff 100644
--- a/YLErpDAL/Modules/RiskEngine/Dto/RuleCondition.cs
+++ b/YLErpDAL/Modules/RiskEngine/Dto/RuleCondition.cs
@@ -7,5 +7,8 @@ namespace YLErp.Modules.RiskEngine.Dto
public string ThresholdType { get; set; }
public object Value { get; set; }
public long? ThresholdVariableId { get; set; }
+ // 介于/不介于 的边界包含控制,默认 true
+ public bool IncludeLowerBound { get; set; } = true;
+ public bool IncludeUpperBound { get; set; } = true;
}
}
diff --git a/YLErpDAL/Modules/RiskEngine/Dto/UpdateRiskApplicationReq.cs b/YLErpDAL/Modules/RiskEngine/Dto/UpdateRiskApplicationReq.cs
index b9af55a9..aa290529 100644
--- a/YLErpDAL/Modules/RiskEngine/Dto/UpdateRiskApplicationReq.cs
+++ b/YLErpDAL/Modules/RiskEngine/Dto/UpdateRiskApplicationReq.cs
@@ -11,7 +11,7 @@ namespace YLErp.Modules.RiskEngine.Dto
public string ScopeClientIds { get; set; }
public string ScopeUnderlyingTypes { get; set; }
public string ScopeTradeTypes { get; set; }
- public bool ScopeIsGlobal { get; set; }
+ public int ScopeIsGlobal { get; set; }
public int Version { get; set; }
}
}
diff --git a/YLErpDAL/Modules/RiskEngine/RiskEngineService.cs b/YLErpDAL/Modules/RiskEngine/RiskEngineService.cs
index 8f4c3470..63aacc30 100644
--- a/YLErpDAL/Modules/RiskEngine/RiskEngineService.cs
+++ b/YLErpDAL/Modules/RiskEngine/RiskEngineService.cs
@@ -845,7 +845,7 @@ namespace YLErp.Modules.RiskEngine
return false;
}
- if (application.ScopeIsGlobal)
+ if (application.ScopeIsGlobal == 1)
{
return true;
}
diff --git a/YLErpDAL/Modules/RiskEngine/RiskRule.cs b/YLErpDAL/Modules/RiskEngine/RiskRule.cs
index 8e8ef067..7b5375b6 100644
--- a/YLErpDAL/Modules/RiskEngine/RiskRule.cs
+++ b/YLErpDAL/Modules/RiskEngine/RiskRule.cs
@@ -10,7 +10,7 @@ namespace YLErp.Modules.RiskEngine
public class RiskRule
{
// === 基础信息 ===
- public int Id { get; set; }
+ public long Id { get; set; }
public string RuleName { get; set; }
public string RuleText { get; set; }
diff --git a/YLErpDAL/Modules/RiskEngine/RiskRuleApplication.cs b/YLErpDAL/Modules/RiskEngine/RiskRuleApplication.cs
index 7b741252..68219350 100644
--- a/YLErpDAL/Modules/RiskEngine/RiskRuleApplication.cs
+++ b/YLErpDAL/Modules/RiskEngine/RiskRuleApplication.cs
@@ -25,7 +25,7 @@ namespace YLErp.Modules.RiskEngine
/// 应用配置主键ID。
/// 用于唯一标识一条规则应用记录。
///
- public int Id { get; set; }
+ public long Id { get; set; }
///
/// 关联的规则ID列表。
@@ -67,7 +67,7 @@ namespace YLErp.Modules.RiskEngine
/// true 表示对所有交易都适用,此时通常忽略其他 Scope 字段;
/// false 表示只在指定范围内适用,需要结合下方各 Scope 字段进行过滤。
///
- public bool ScopeIsGlobal { get; set; }
+ public int ScopeIsGlobal { get; set; }
///
/// 适用的资产簿记账户范围。
diff --git a/YLErpDAL/Modules/RiskEngine/RiskRuleService.cs b/YLErpDAL/Modules/RiskEngine/RiskRuleService.cs
index 4e082af5..08421a07 100644
--- a/YLErpDAL/Modules/RiskEngine/RiskRuleService.cs
+++ b/YLErpDAL/Modules/RiskEngine/RiskRuleService.cs
@@ -1,6 +1,7 @@
using BaseOUDAL;
using Newtonsoft.Json;
using Qdp.Foundation.Utilities;
+using System.Linq.Expressions;
using YLErp.BLL;
using YLErp.DBModels;
using YLErp.Model;
@@ -202,7 +203,7 @@ namespace YLErp.Modules.RiskEngine
private static readonly Dictionary> ValidOperatorsByType = new Dictionary>
{
{ RiskVariableDataType.Numeric, new HashSet { ">", "<", ">=", "<=", "=", "≠", "介于", "不介于" } },
- { RiskVariableDataType.Date, new HashSet { "<", ">", "=", ">=", "<=", "介于", "不介于" } },
+ { RiskVariableDataType.Date, new HashSet { "早于", "晚于", "等于", "不早于", "不晚于", "介于", "不介于" } },
{ RiskVariableDataType.Boolean, new HashSet { "是", "否" } }
};
@@ -291,15 +292,35 @@ namespace YLErp.Modules.RiskEngine
{
if (cond.Value == null)
throw new ServiceException($"{condLabel}:固定阈值不能为空");
- if (variableDef.DataType == RiskVariableDataType.Numeric)
+
+ if (cond.Operator == "介于" || cond.Operator == "不介于")
{
- if (!decimal.TryParse(cond.Value.ToString(), out _))
- throw new ServiceException($"{condLabel}:数值型变量的阈值必须为数字");
+ // 介于/不介于:Value 必须为双元素数组 [下限, 上限]
+ if (!(cond.Value is Newtonsoft.Json.Linq.JArray arr && arr.Count == 2))
+ throw new ServiceException($"{condLabel}:操作符 '{cond.Operator}' 的阈值必须为双元素数组 [下限, 上限]");
+ if (variableDef.DataType == RiskVariableDataType.Numeric)
+ {
+ if (!decimal.TryParse(arr[0].ToString(), out _) || !decimal.TryParse(arr[1].ToString(), out _))
+ throw new ServiceException($"{condLabel}:数值型介于/不介于的下限和上限必须为数字");
+ }
+ if (variableDef.DataType == RiskVariableDataType.Date)
+ {
+ if (!DateTime.TryParse(arr[0].ToString(), out _) || !DateTime.TryParse(arr[1].ToString(), out _))
+ throw new ServiceException($"{condLabel}:日期型介于/不介于的起始和结束日期必须为合法日期");
+ }
}
- if (variableDef.DataType == RiskVariableDataType.Date)
+ else
{
- if (!DateTime.TryParse(cond.Value.ToString(), out _))
- throw new ServiceException($"{condLabel}:日期型变量的阈值必须为合法日期");
+ if (variableDef.DataType == RiskVariableDataType.Numeric)
+ {
+ if (!decimal.TryParse(cond.Value.ToString(), out _))
+ throw new ServiceException($"{condLabel}:数值型变量的阈值必须为数字");
+ }
+ if (variableDef.DataType == RiskVariableDataType.Date)
+ {
+ if (!DateTime.TryParse(cond.Value.ToString(), out _))
+ throw new ServiceException($"{condLabel}:日期型变量的阈值必须为合法日期");
+ }
}
}
else if (cond.ThresholdType == "Variable")
@@ -356,7 +377,7 @@ namespace YLErp.Modules.RiskEngine
private void ValidateScopeFields(CreateRiskApplicationReq req)
{
- if (req.ScopeIsGlobal)
+ if (req.ScopeIsGlobal == 1)
{
if (!string.IsNullOrEmpty(req.ScopeAssetBookIds) ||
!string.IsNullOrEmpty(req.ScopeClientIds) ||
@@ -513,6 +534,71 @@ namespace YLErp.Modules.RiskEngine
return string.Join(", ", names);
}
+ ///
+ /// 构建 Scope 字段的 OR 过滤谓词(逗号分隔值精确匹配)
+ ///
+ private static IQueryable ApplyScopeFilter(
+ IQueryable query,
+ Expression> fieldSelector,
+ string csvValues)
+ {
+ var ids = csvValues.Split(',', StringSplitOptions.RemoveEmptyEntries);
+ if (ids.Length == 0)
+ return query;
+
+ Expression> predicate = null;
+ var param = fieldSelector.Parameters[0];
+ var member = fieldSelector.Body;
+
+ foreach (var trimmed in ids.Select(id => id.Trim()))
+ {
+ var eq = Expression.Equal(member, Expression.Constant(trimmed));
+ var startsExpr = Expression.Call(member, nameof(string.StartsWith), null,
+ Expression.Constant(trimmed + ","));
+ var endsExpr = Expression.Call(member, nameof(string.EndsWith), null,
+ Expression.Constant("," + trimmed));
+ var containsExpr = Expression.Call(member, nameof(string.Contains), null,
+ Expression.Constant("," + trimmed + ","));
+
+ var orExpr = Expression.OrElse(Expression.OrElse(eq, startsExpr),
+ Expression.OrElse(endsExpr, containsExpr));
+ var lambda = Expression.Lambda>(orExpr, param);
+ predicate = predicate == null ? lambda : predicate.Or(lambda);
+ }
+
+ return predicate != null ? query.Where(predicate) : query;
+ }
+
+ private static string GetStrategyName(RiskControlStrategy strategy)
+ {
+ return strategy switch
+ {
+ RiskControlStrategy.Block => "阻断",
+ RiskControlStrategy.Approval => "审批",
+ RiskControlStrategy.ShowTip => "提醒",
+ _ => strategy.ToString()
+ };
+ }
+
+ private static readonly Dictionary TriggerPointCnMap = new Dictionary
+ {
+ ["BOOK_CONFIRM"] = "交易录入确认",
+ ["CLOSE_REVIEW"] = "平仓审核",
+ ["UPLOAD_CONFIRMATION"] = "上传确认书",
+ ["EVENT_TRIGGER"] = "事件触发",
+ ["FUND_PAYMENT"] = "资金支付"
+ };
+
+ private static string MapTriggerPointsToChinese(string triggerPoints)
+ {
+ if (string.IsNullOrWhiteSpace(triggerPoints))
+ return "";
+
+ var parts = triggerPoints.Split(',');
+ var translated = parts.Select(p => TriggerPointCnMap.TryGetValue(p.Trim(), out var cn) ? cn : p.Trim());
+ return string.Join(", ", translated);
+ }
+
#endregion
#region Rule Management
@@ -813,7 +899,7 @@ namespace YLErp.Modules.RiskEngine
{
Id = app.id,
RuleIds = app.RuleIds,
- Status = app.Status,
+ Status = (int)app.Status,
ControlStrategy = app.ControlStrategy,
TriggerPoints = app.TriggerPoints,
ScopeAssetBookIds = app.ScopeAssetBookIds,
@@ -878,12 +964,24 @@ namespace YLErp.Modules.RiskEngine
&& r.RuleName.Contains(req.RuleName)));
}
+ if (!string.IsNullOrWhiteSpace(req.ScopeClientIds))
+ query = ApplyScopeFilter(query, a => a.ScopeClientIds, req.ScopeClientIds);
+
+ if (!string.IsNullOrWhiteSpace(req.ScopeUnderlyingTypes))
+ query = ApplyScopeFilter(query, a => a.ScopeUnderlyingTypes, req.ScopeUnderlyingTypes);
+
+ if (!string.IsNullOrWhiteSpace(req.ScopeTradeTypes))
+ query = ApplyScopeFilter(query, a => a.ScopeTradeTypes, req.ScopeTradeTypes);
+
+ if (!string.IsNullOrWhiteSpace(req.ScopeAssetBookIds))
+ query = ApplyScopeFilter(query, a => a.ScopeAssetBookIds, req.ScopeAssetBookIds);
+
var pagedResult = query.OrderByDescending(a => a.UpdateDate)
.Select(a => new RiskApplicationListItem
{
Id = a.id,
RuleIds = a.RuleIds,
- Status = a.Status,
+ Status = (int)a.Status,
ControlStrategy = a.ControlStrategy,
TriggerPoints = a.TriggerPoints,
ScopeAssetBookIds = a.ScopeAssetBookIds,
@@ -962,7 +1060,7 @@ namespace YLErp.Modules.RiskEngine
DbContext.SaveChanges();
WriteAuditLog("APP_CREATE", "APPLICATION", entity.id, ResolveRuleNames(req.RuleIds),
- $"创建应用配置:策略={req.ControlStrategy}, 触发时点={req.TriggerPoints}",
+ $"创建应用配置:策略={GetStrategyName(req.ControlStrategy)}, 触发时点={MapTriggerPointsToChinese(req.TriggerPoints)}",
snapshotData: JsonConvert.SerializeObject(new { Version = entity.Version }));
DbContext.SaveChanges();
@@ -1016,7 +1114,7 @@ namespace YLErp.Modules.RiskEngine
app.UpdateDate = DateTime.Now;
WriteAuditLog("APP_UPDATE", "APPLICATION", applicationId, ResolveRuleNames(app.RuleIds),
- $"修改应用配置:策略={req.ControlStrategy}, 触发时点={req.TriggerPoints}");
+ $"修改应用配置:策略={GetStrategyName(req.ControlStrategy)}, 触发时点={MapTriggerPointsToChinese(req.TriggerPoints)}");
DbContext.SaveChanges();
TryRefreshCache();
@@ -1034,7 +1132,7 @@ namespace YLErp.Modules.RiskEngine
app.UpdateOptName = UserName;
app.UpdateDate = DateTime.Now;
- WriteAuditLog("APPLICATION_DELETE", "APPLICATION", applicationId, ResolveRuleNames(app.RuleIds), "删除应用配置");
+ WriteAuditLog("APP_DELETE", "APPLICATION", applicationId, ResolveRuleNames(app.RuleIds), "删除应用配置");
DbContext.SaveChanges();
TryRefreshCache();
@@ -1127,7 +1225,7 @@ namespace YLErp.Modules.RiskEngine
app.UpdateOptName = UserName;
app.UpdateDate = DateTime.Now;
- WriteAuditLog("APPLICATION_BATCH_DISABLE", "APPLICATION", app.id, ResolveRuleNames(app.RuleIds), "批量停用应用配置");
+ WriteAuditLog("APP_BATCH_DISABLE", "APPLICATION", app.id, ResolveRuleNames(app.RuleIds), "批量停用应用配置");
}
DbContext.SaveChanges();
@@ -1154,6 +1252,11 @@ namespace YLErp.Modules.RiskEngine
query = query.Where(v => v.Category == req.Category.Value);
}
+ if (req.DataType.HasValue)
+ {
+ query = query.Where(v => v.DataType == req.DataType.Value);
+ }
+
if (!string.IsNullOrWhiteSpace(req.VariableName))
{
query = query.Where(v => v.VariableName.Contains(req.VariableName));
@@ -1358,19 +1461,36 @@ namespace YLErp.Modules.RiskEngine
query = query.Where(l => l.OperationType == req.OperationType);
}
+ if (!string.IsNullOrWhiteSpace(req.OperationTypes))
+ {
+ var types = req.OperationTypes.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
+ query = query.Where(l => types.Contains(l.OperationType));
+ }
+
if (!string.IsNullOrWhiteSpace(req.TargetType))
{
query = query.Where(l => l.TargetType == req.TargetType);
}
+ if (!string.IsNullOrWhiteSpace(req.TargetName))
+ {
+ query = query.Where(l => l.TargetName.Contains(req.TargetName));
+ }
+
+ if (!string.IsNullOrWhiteSpace(req.OptName))
+ {
+ query = query.Where(l => l.OptName.Contains(req.OptName));
+ }
+
if (req.StartDate.HasValue)
{
- query = query.Where(l => l.OptDate >= req.StartDate.Value);
+ query = query.Where(l => l.OptDate >= req.StartDate.Value.Date);
}
if (req.EndDate.HasValue)
{
- query = query.Where(l => l.OptDate <= req.EndDate.Value);
+ var end = req.EndDate.Value.Date.AddDays(1);
+ query = query.Where(l => l.OptDate < end);
}
if (!string.IsNullOrWhiteSpace(req.Keyword))
diff --git a/YLErpWeb/App_Data/FunctionRight.xml b/YLErpWeb/App_Data/FunctionRight.xml
index 1e03e280..ed07a284 100644
--- a/YLErpWeb/App_Data/FunctionRight.xml
+++ b/YLErpWeb/App_Data/FunctionRight.xml
@@ -62,21 +62,21 @@
-
+
-
+
-
+
-
+
diff --git a/YLErpWeb/App_Data/Menus.txt b/YLErpWeb/App_Data/Menus.txt
index a8aea562..506f2a79 100644
--- a/YLErpWeb/App_Data/Menus.txt
+++ b/YLErpWeb/App_Data/Menus.txt
@@ -25,6 +25,7 @@
{Name:"资金监控",Rights:["风险控制-资金监控"],Url:"client/clientRiskMonitor"},
{Name:"市场风险",Rights:["风险控制-市场风险"],Url:"risk/RiskExposureReport"},
{Name:"限额监控",Rights:["风险控制-限额监控"],Url:"risk/quotaMonitor"},
+ {Name:"异常交易监控",Rights:["风险控制-异常交易监控"],Url:"v3/risk/risk-engine-config"},
{Name:"白名单券池",Rights:["风险控制-白名单券池"],Url:"v3/data/underlying-pool"},
{Name:"日终持仓风险",Rights:["风险控制-日终持仓风险"],Url:"trade/EodPositionRisks"},
{Name:"日终持仓风险_互换",Rights:["风险控制-日终持仓风险_互换"],Url:"swaptrade2/EodPositionRisks"},
diff --git a/YLErpWeb/Common/BaseController.cs b/YLErpWeb/Common/BaseController.cs
index be2e8e8a..e8224105 100644
--- a/YLErpWeb/Common/BaseController.cs
+++ b/YLErpWeb/Common/BaseController.cs
@@ -180,14 +180,6 @@ namespace YLErp.Web
return;
}
var hasRight = false;
- #if DEBUG
- if (context.Controller is Controllers.RiskRuleController)
- {
- hasRight = true;
- base.OnActionExecuting(context);
- return;
- }
- #endif
var isAjaxRequest = Request.Headers["X-Requested-With"] == "XMLHttpRequest";
var typedHeaders = Request.GetTypedHeaders();
diff --git a/YLErpWeb/Controllers/RiskRuleController.cs b/YLErpWeb/Controllers/RiskRuleController.cs
index 99158235..c6f238a3 100644
--- a/YLErpWeb/Controllers/RiskRuleController.cs
+++ b/YLErpWeb/Controllers/RiskRuleController.cs
@@ -1,4 +1,4 @@
-using Qdp.Foundation.Utilities;
+using Qdp.Foundation.Utilities;
using YLErp.DBModels;
using YLErp.Modules.RiskEngine;
using YLErp.Modules.RiskEngine.Dto;
@@ -13,7 +13,7 @@ namespace YLErp.Web.Controllers
#region Rule Management
[HttpGet("risk-rules")]
- [MyAuthorize("风控规则查看")]
+ [MyAuthorize("风险控制-风控规则查看")]
public JsonResult QueryRiskRules(QueryRiskRuleReq req)
{
try
@@ -34,7 +34,7 @@ namespace YLErp.Web.Controllers
}
[HttpGet("risk-rules/{id}")]
- [MyAuthorize("风控规则查看")]
+ [MyAuthorize("风险控制-风控规则查看")]
public JsonResult GetRiskRule(long id)
{
try
@@ -55,7 +55,7 @@ namespace YLErp.Web.Controllers
}
[HttpGet("risk-rules/{id}/versions")]
- [MyAuthorize("风控规则查看")]
+ [MyAuthorize("风险控制-风控规则查看")]
public JsonResult GetRiskRuleVersions(long id)
{
try
@@ -76,7 +76,7 @@ namespace YLErp.Web.Controllers
}
[HttpPost("risk-rules")]
- [MyAuthorize("风控规则新增")]
+ [MyAuthorize("风险控制-风控规则新增")]
public JsonResult CreateRiskRule([FromBody] CreateRiskRuleReq req)
{
try
@@ -97,7 +97,7 @@ namespace YLErp.Web.Controllers
}
[HttpPut("risk-rules/{id}")]
- [MyAuthorize("风控规则编辑")]
+ [MyAuthorize("风险控制-风控规则编辑")]
public JsonResult UpdateRiskRule(long id, [FromBody] UpdateRiskRuleReq req)
{
try
@@ -118,7 +118,7 @@ namespace YLErp.Web.Controllers
}
[HttpDelete("risk-rules/{id}")]
- [MyAuthorize("风控规则删除")]
+ [MyAuthorize("风险控制-风控规则删除")]
public JsonResult DeleteRiskRule(long id)
{
try
@@ -139,7 +139,7 @@ namespace YLErp.Web.Controllers
}
[HttpDelete("risk-rules/batch")]
- [MyAuthorize("风控规则删除")]
+ [MyAuthorize("风险控制-风控规则删除")]
public JsonResult BatchDeleteRiskRules([FromBody] List ids)
{
try
@@ -160,7 +160,7 @@ namespace YLErp.Web.Controllers
}
[HttpPost("risk-rules/{id}/enable")]
- [MyAuthorize("风控规则启停")]
+ [MyAuthorize("风险控制-风控规则启停")]
public JsonResult EnableRiskRule(long id)
{
try
@@ -181,7 +181,7 @@ namespace YLErp.Web.Controllers
}
[HttpPost("risk-rules/{id}/disable")]
- [MyAuthorize("风控规则启停")]
+ [MyAuthorize("风险控制-风控规则启停")]
public JsonResult DisableRiskRule(long id)
{
try
@@ -202,7 +202,7 @@ namespace YLErp.Web.Controllers
}
[HttpGet("risk-rules/{id}/applications")]
- [MyAuthorize("风控规则查看")]
+ [MyAuthorize("风险控制-风控规则查看")]
public JsonResult GetRuleApplications(long id)
{
try
@@ -223,7 +223,7 @@ namespace YLErp.Web.Controllers
}
[HttpGet("risk-rules/list")]
- [MyAuthorize("风控规则查看")]
+ [MyAuthorize("风险控制-风控规则查看")]
public JsonResult GetAllRiskRules()
{
try
@@ -248,7 +248,7 @@ namespace YLErp.Web.Controllers
#region Application Management
[HttpGet("risk-applications")]
- [MyAuthorize("风控应用查看")]
+ [MyAuthorize("风险控制-风控应用查看")]
public JsonResult QueryRiskApplications(QueryRiskApplicationReq req)
{
try
@@ -269,7 +269,7 @@ namespace YLErp.Web.Controllers
}
[HttpGet("risk-applications/{id}")]
- [MyAuthorize("风控应用查看")]
+ [MyAuthorize("风险控制-风控应用查看")]
public JsonResult GetRiskApplication(long id)
{
try
@@ -290,7 +290,7 @@ namespace YLErp.Web.Controllers
}
[HttpPost("risk-applications")]
- [MyAuthorize("风控应用新增")]
+ [MyAuthorize("风险控制-风控应用新增")]
public JsonResult CreateRiskApplication([FromBody] CreateRiskApplicationReq req)
{
try
@@ -311,7 +311,7 @@ namespace YLErp.Web.Controllers
}
[HttpPut("risk-applications/{id}")]
- [MyAuthorize("风控应用编辑")]
+ [MyAuthorize("风险控制-风控应用编辑")]
public JsonResult UpdateRiskApplication(long id, [FromBody] UpdateRiskApplicationReq req)
{
try
@@ -332,7 +332,7 @@ namespace YLErp.Web.Controllers
}
[HttpDelete("risk-applications/{id}")]
- [MyAuthorize("风控应用删除")]
+ [MyAuthorize("风险控制-风控应用删除")]
public JsonResult DeleteRiskApplication(long id)
{
try
@@ -353,7 +353,7 @@ namespace YLErp.Web.Controllers
}
[HttpPost("risk-applications/{id}/enable")]
- [MyAuthorize("风控应用启停")]
+ [MyAuthorize("风险控制-风控应用启停")]
public JsonResult EnableRiskApplication(long id)
{
try
@@ -374,7 +374,7 @@ namespace YLErp.Web.Controllers
}
[HttpPost("risk-applications/{id}/disable")]
- [MyAuthorize("风控应用启停")]
+ [MyAuthorize("风险控制-风控应用启停")]
public JsonResult DisableRiskApplication(long id)
{
try
@@ -395,7 +395,7 @@ namespace YLErp.Web.Controllers
}
[HttpPost("risk-applications/batch-enable")]
- [MyAuthorize("风控应用启停")]
+ [MyAuthorize("风险控制-风控应用启停")]
public JsonResult BatchEnableRiskApplications([FromBody] List ids)
{
try
@@ -416,7 +416,7 @@ namespace YLErp.Web.Controllers
}
[HttpPost("risk-applications/batch-disable")]
- [MyAuthorize("风控应用启停")]
+ [MyAuthorize("风险控制-风控应用启停")]
public JsonResult BatchDisableRiskApplications([FromBody] List ids)
{
try
@@ -441,7 +441,7 @@ namespace YLErp.Web.Controllers
#region Variable Management
[HttpGet("risk-variables")]
- [MyAuthorize("风控变量查看")]
+ [MyAuthorize("风险控制-风控变量查看")]
public JsonResult QueryRiskVariables(QueryRiskVariableReq req)
{
try
@@ -462,7 +462,7 @@ namespace YLErp.Web.Controllers
}
[HttpGet("risk-variables/{id}")]
- [MyAuthorize("风控变量查看")]
+ [MyAuthorize("风险控制-风控变量查看")]
public JsonResult GetRiskVariable(long id)
{
try
@@ -483,7 +483,7 @@ namespace YLErp.Web.Controllers
}
[HttpGet("risk-variables/list")]
- [MyAuthorize("风控变量查看")]
+ [MyAuthorize("风险控制-风控变量查看")]
public JsonResult GetAllRiskVariables()
{
try
@@ -504,7 +504,7 @@ namespace YLErp.Web.Controllers
}
[HttpPost("risk-variables")]
- [MyAuthorize("风控变量新增")]
+ [MyAuthorize("风险控制-风控变量新增")]
public JsonResult CreateRiskVariable([FromBody] CreateRiskVariableReq req)
{
try
@@ -525,7 +525,7 @@ namespace YLErp.Web.Controllers
}
[HttpPut("risk-variables/{id}")]
- [MyAuthorize("风控变量编辑")]
+ [MyAuthorize("风险控制-风控变量编辑")]
public JsonResult UpdateRiskVariable(long id, [FromBody] UpdateRiskVariableReq req)
{
try
@@ -546,7 +546,7 @@ namespace YLErp.Web.Controllers
}
[HttpDelete("risk-variables/{id}")]
- [MyAuthorize("风控变量删除")]
+ [MyAuthorize("风险控制-风控变量删除")]
public JsonResult DeleteRiskVariable(long id)
{
try
@@ -595,7 +595,7 @@ namespace YLErp.Web.Controllers
#region Trade Types
[HttpGet("trade-types")]
- [MyAuthorize("风控应用查看")]
+ [MyAuthorize("风险控制-风控应用查看")]
public JsonResult GetTradeTypes()
{
try
@@ -624,7 +624,7 @@ namespace YLErp.Web.Controllers
#region Audit Log
[HttpGet("risk-audit-logs")]
- [MyAuthorize("风控日志查看")]
+ [MyAuthorize("风险控制-风控日志查看")]
public JsonResult QueryRiskAuditLogs(QueryRiskAuditLogReq req)
{
try
@@ -645,7 +645,7 @@ namespace YLErp.Web.Controllers
}
[HttpGet("risk-audit-logs/{id}")]
- [MyAuthorize("风控日志查看")]
+ [MyAuthorize("风险控制-风控日志查看")]
public JsonResult GetRiskAuditLogDetail(long id)
{
try
@@ -666,7 +666,7 @@ namespace YLErp.Web.Controllers
}
[HttpGet("risk-audit-logs/export")]
- [MyAuthorize("风控日志导出")]
+ [MyAuthorize("风险控制-风控日志导出")]
public IActionResult ExportRiskAuditLogs(QueryRiskAuditLogReq req)
{
try