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