From d7c09c793a488cec9699746fa0ce7d17ff040a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=B9=E5=B3=B0?= Date: Mon, 29 Jun 2026 18:09:19 +0800 Subject: [PATCH 1/6] =?UTF-8?q?fix(risk-engine):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=A4=9A=E4=B8=AA=E9=A3=8E=E6=8E=A7=E5=BC=95=E6=93=8E=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ScopeIsGlobal 类型由 bool 改为 int 以兼容前端传输 0/1 - 修复 QueryApplicationList 中 Status 投影 EF Core enum 转换失败 - 新增 Scope 字段查询支持(逗号分隔集合精确匹配) - 新增变量列表 DataType 筛选 - 修复审计日志日期查询范围(EndDate 纳入整天数据) - 统一 Application 审计日志 OperationType 前缀(APP_xxx) - 审计日志 OperationDetail 枚举值映射为中文 --- .../DBModels/glms_risk_rule_application.cs | 2 +- .../DbUpdate/Ver-5.6.0/seed_rules.sql | 7 +- .../RiskEngine/Compile/RuleCompiler.cs | 7 + .../Dto/CreateRiskApplicationReq.cs | 2 +- .../RiskEngine/Dto/QueryRiskApplicationReq.cs | 4 + .../RiskEngine/Dto/QueryRiskVariableReq.cs | 1 + .../RiskEngine/Dto/RiskApplicationDetail.cs | 2 +- .../RiskEngine/Dto/RiskApplicationListItem.cs | 4 +- .../Modules/RiskEngine/Dto/RuleCondition.cs | 3 + .../Dto/UpdateRiskApplicationReq.cs | 2 +- .../Modules/RiskEngine/RiskEngineService.cs | 2 +- .../Modules/RiskEngine/RiskRuleApplication.cs | 2 +- .../Modules/RiskEngine/RiskRuleService.cs | 161 ++++++++++++++++-- YLErpWeb/App_Data/Menus.txt | 1 + 14 files changed, 173 insertions(+), 27 deletions(-) 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_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 0d2f778f..85875f15 100644 --- a/YLErpDAL/Modules/RiskEngine/Compile/RuleCompiler.cs +++ b/YLErpDAL/Modules/RiskEngine/Compile/RuleCompiler.cs @@ -304,12 +304,19 @@ namespace YLErp.Modules.RiskEngine { return op?.Trim() switch { + // 数值型 C# 符号 "=" or "==" => "==", "!=" or "≠" => "!=", ">" => ">", "<" => "<", ">=" => ">=", "<=" => "<=", + // 日期型中文语义 → C# 符号 + "早于" => "<", + "晚于" => ">", + "等于" => "==", + "不早于" => ">=", + "不晚于" => "<=", _ => throw new ArgumentException($"不支持的操作符:{op}") }; } 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/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 b357f444..70561bd5 100644 --- a/YLErpDAL/Modules/RiskEngine/RiskEngineService.cs +++ b/YLErpDAL/Modules/RiskEngine/RiskEngineService.cs @@ -436,7 +436,7 @@ namespace YLErp.Modules.RiskEngine return false; } - if (application.ScopeIsGlobal) + if (application.ScopeIsGlobal == 1) { return true; } diff --git a/YLErpDAL/Modules/RiskEngine/RiskRuleApplication.cs b/YLErpDAL/Modules/RiskEngine/RiskRuleApplication.cs index 7b741252..9e186dbf 100644 --- a/YLErpDAL/Modules/RiskEngine/RiskRuleApplication.cs +++ b/YLErpDAL/Modules/RiskEngine/RiskRuleApplication.cs @@ -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..d8f1316f 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,36 @@ namespace YLErp.Modules.RiskEngine return string.Join(", ", names); } + 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 +864,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 +929,84 @@ namespace YLErp.Modules.RiskEngine && r.RuleName.Contains(req.RuleName))); } + if (!string.IsNullOrWhiteSpace(req.ScopeClientIds)) + { + var ids = req.ScopeClientIds.Split(',', StringSplitOptions.RemoveEmptyEntries); + Expression> scopePredicate = null; + foreach (var id in ids) + { + var idCopy = id; + Expression> expr = a => + a.ScopeClientIds == idCopy || + a.ScopeClientIds.StartsWith(idCopy + ",") || + a.ScopeClientIds.EndsWith("," + idCopy) || + a.ScopeClientIds.Contains("," + idCopy + ","); + scopePredicate = scopePredicate == null ? expr : scopePredicate.Or(expr); + } + if (scopePredicate != null) + query = query.Where(scopePredicate); + } + + if (!string.IsNullOrWhiteSpace(req.ScopeUnderlyingTypes)) + { + var types = req.ScopeUnderlyingTypes.Split(',', StringSplitOptions.RemoveEmptyEntries); + Expression> scopePredicate = null; + foreach (var type in types) + { + var typeCopy = type; + Expression> expr = a => + a.ScopeUnderlyingTypes == typeCopy || + a.ScopeUnderlyingTypes.StartsWith(typeCopy + ",") || + a.ScopeUnderlyingTypes.EndsWith("," + typeCopy) || + a.ScopeUnderlyingTypes.Contains("," + typeCopy + ","); + scopePredicate = scopePredicate == null ? expr : scopePredicate.Or(expr); + } + if (scopePredicate != null) + query = query.Where(scopePredicate); + } + + if (!string.IsNullOrWhiteSpace(req.ScopeTradeTypes)) + { + var types = req.ScopeTradeTypes.Split(',', StringSplitOptions.RemoveEmptyEntries); + Expression> scopePredicate = null; + foreach (var type in types) + { + var typeCopy = type; + Expression> expr = a => + a.ScopeTradeTypes == typeCopy || + a.ScopeTradeTypes.StartsWith(typeCopy + ",") || + a.ScopeTradeTypes.EndsWith("," + typeCopy) || + a.ScopeTradeTypes.Contains("," + typeCopy + ","); + scopePredicate = scopePredicate == null ? expr : scopePredicate.Or(expr); + } + if (scopePredicate != null) + query = query.Where(scopePredicate); + } + + if (!string.IsNullOrWhiteSpace(req.ScopeAssetBookIds)) + { + var ids = req.ScopeAssetBookIds.Split(',', StringSplitOptions.RemoveEmptyEntries); + Expression> scopePredicate = null; + foreach (var id in ids) + { + var idCopy = id; + Expression> expr = a => + a.ScopeAssetBookIds == idCopy || + a.ScopeAssetBookIds.StartsWith(idCopy + ",") || + a.ScopeAssetBookIds.EndsWith("," + idCopy) || + a.ScopeAssetBookIds.Contains("," + idCopy + ","); + scopePredicate = scopePredicate == null ? expr : scopePredicate.Or(expr); + } + if (scopePredicate != null) + query = query.Where(scopePredicate); + } + 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 +1085,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 +1139,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 +1157,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 +1250,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 +1277,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)); @@ -1365,12 +1493,13 @@ namespace YLErp.Modules.RiskEngine 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/Menus.txt b/YLErpWeb/App_Data/Menus.txt index a8aea562..7b460406 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"}, From 10b08f8f211844d1ff8b936596ab65a3760cb3e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=B9=E5=B3=B0?= Date: Mon, 29 Jun 2026 18:34:46 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Modules/RiskEngine/RiskEngineService.cs | 2 +- YLErpDAL/Modules/RiskEngine/RiskRule.cs | 2 +- .../Modules/RiskEngine/RiskRuleApplication.cs | 2 +- .../Modules/RiskEngine/RiskRuleService.cs | 103 +++++++----------- 4 files changed, 42 insertions(+), 67 deletions(-) diff --git a/YLErpDAL/Modules/RiskEngine/RiskEngineService.cs b/YLErpDAL/Modules/RiskEngine/RiskEngineService.cs index 3d040b9f..2e0e68a8 100644 --- a/YLErpDAL/Modules/RiskEngine/RiskEngineService.cs +++ b/YLErpDAL/Modules/RiskEngine/RiskEngineService.cs @@ -157,7 +157,7 @@ namespace YLErp.Modules.RiskEngine var rules = LoadRulesFromDb(); var applications = LoadApplicationsFromDb(); - List res = new List(); + List res = new List(); foreach(var i in applications) { if(i.Status!= RiskRuleStatus.Active) diff --git a/YLErpDAL/Modules/RiskEngine/RiskRule.cs b/YLErpDAL/Modules/RiskEngine/RiskRule.cs index 5558c2b4..bc6c6910 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 9e186dbf..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列表。 diff --git a/YLErpDAL/Modules/RiskEngine/RiskRuleService.cs b/YLErpDAL/Modules/RiskEngine/RiskRuleService.cs index d8f1316f..7e79f074 100644 --- a/YLErpDAL/Modules/RiskEngine/RiskRuleService.cs +++ b/YLErpDAL/Modules/RiskEngine/RiskRuleService.cs @@ -534,6 +534,41 @@ 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 @@ -930,76 +965,16 @@ namespace YLErp.Modules.RiskEngine } if (!string.IsNullOrWhiteSpace(req.ScopeClientIds)) - { - var ids = req.ScopeClientIds.Split(',', StringSplitOptions.RemoveEmptyEntries); - Expression> scopePredicate = null; - foreach (var id in ids) - { - var idCopy = id; - Expression> expr = a => - a.ScopeClientIds == idCopy || - a.ScopeClientIds.StartsWith(idCopy + ",") || - a.ScopeClientIds.EndsWith("," + idCopy) || - a.ScopeClientIds.Contains("," + idCopy + ","); - scopePredicate = scopePredicate == null ? expr : scopePredicate.Or(expr); - } - if (scopePredicate != null) - query = query.Where(scopePredicate); - } + query = ApplyScopeFilter(query, a => a.ScopeClientIds, req.ScopeClientIds); if (!string.IsNullOrWhiteSpace(req.ScopeUnderlyingTypes)) - { - var types = req.ScopeUnderlyingTypes.Split(',', StringSplitOptions.RemoveEmptyEntries); - Expression> scopePredicate = null; - foreach (var type in types) - { - var typeCopy = type; - Expression> expr = a => - a.ScopeUnderlyingTypes == typeCopy || - a.ScopeUnderlyingTypes.StartsWith(typeCopy + ",") || - a.ScopeUnderlyingTypes.EndsWith("," + typeCopy) || - a.ScopeUnderlyingTypes.Contains("," + typeCopy + ","); - scopePredicate = scopePredicate == null ? expr : scopePredicate.Or(expr); - } - if (scopePredicate != null) - query = query.Where(scopePredicate); - } + query = ApplyScopeFilter(query, a => a.ScopeUnderlyingTypes, req.ScopeUnderlyingTypes); if (!string.IsNullOrWhiteSpace(req.ScopeTradeTypes)) - { - var types = req.ScopeTradeTypes.Split(',', StringSplitOptions.RemoveEmptyEntries); - Expression> scopePredicate = null; - foreach (var type in types) - { - var typeCopy = type; - Expression> expr = a => - a.ScopeTradeTypes == typeCopy || - a.ScopeTradeTypes.StartsWith(typeCopy + ",") || - a.ScopeTradeTypes.EndsWith("," + typeCopy) || - a.ScopeTradeTypes.Contains("," + typeCopy + ","); - scopePredicate = scopePredicate == null ? expr : scopePredicate.Or(expr); - } - if (scopePredicate != null) - query = query.Where(scopePredicate); - } + query = ApplyScopeFilter(query, a => a.ScopeTradeTypes, req.ScopeTradeTypes); if (!string.IsNullOrWhiteSpace(req.ScopeAssetBookIds)) - { - var ids = req.ScopeAssetBookIds.Split(',', StringSplitOptions.RemoveEmptyEntries); - Expression> scopePredicate = null; - foreach (var id in ids) - { - var idCopy = id; - Expression> expr = a => - a.ScopeAssetBookIds == idCopy || - a.ScopeAssetBookIds.StartsWith(idCopy + ",") || - a.ScopeAssetBookIds.EndsWith("," + idCopy) || - a.ScopeAssetBookIds.Contains("," + idCopy + ","); - scopePredicate = scopePredicate == null ? expr : scopePredicate.Or(expr); - } - if (scopePredicate != null) - query = query.Where(scopePredicate); - } + query = ApplyScopeFilter(query, a => a.ScopeAssetBookIds, req.ScopeAssetBookIds); var pagedResult = query.OrderByDescending(a => a.UpdateDate) .Select(a => new RiskApplicationListItem From 5caad4d0ffa69db64530d1ab97dc8404d20e5b5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=B9=E5=B3=B0?= Date: Tue, 30 Jun 2026 15:05:34 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E4=BF=AE=E6=94=B9URL=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- YLErpWeb/App_Data/Menus.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YLErpWeb/App_Data/Menus.txt b/YLErpWeb/App_Data/Menus.txt index 7b460406..506f2a79 100644 --- a/YLErpWeb/App_Data/Menus.txt +++ b/YLErpWeb/App_Data/Menus.txt @@ -25,7 +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/risk/risk-engine-config"}, {Name:"白名单券池",Rights:["风险控制-白名单券池"],Url:"v3/data/underlying-pool"}, {Name:"日终持仓风险",Rights:["风险控制-日终持仓风险"],Url:"trade/EodPositionRisks"}, {Name:"日终持仓风险_互换",Rights:["风险控制-日终持仓风险_互换"],Url:"swaptrade2/EodPositionRisks"}, From f53ef952220745e1af919ad7a90718dc8a479f8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=B9=E5=B3=B0?= Date: Tue, 30 Jun 2026 16:56:14 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=A3=8E=E6=8E=A7?= =?UTF-8?q?=E8=A7=84=E5=88=99=E6=93=8D=E4=BD=9C=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Ver-5.6.0/seed_menu_risk_alert.sql | 18 ++++++++++++++++++ YLErpWeb/App_Data/FunctionRight.xml | 8 ++++---- 2 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 Framework/YLErp.Resources/DbUpdate/Ver-5.6.0/seed_menu_risk_alert.sql 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..3ab5fb65 --- /dev/null +++ b/Framework/YLErp.Resources/DbUpdate/Ver-5.6.0/seed_menu_risk_alert.sql @@ -0,0 +1,18 @@ +-- ============================================================ +-- 异常交易监控页面 - 操作权限(按钮)数据 +-- 依赖:异常交易监控菜单 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, NULL, 0, '', 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); 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 @@ - + - + - + - + From 29ac61e2d51aeb5a45924cbae8bfdae0fff59142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=B9=E5=B3=B0?= Date: Tue, 30 Jun 2026 19:44:20 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=A3=8E=E6=8E=A7?= =?UTF-8?q?=E8=A7=84=E5=88=99=E6=93=8D=E4=BD=9C=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Ver-5.6.0/seed_menu_risk_alert.sql | 36 ++++++++++- YLErpWeb/Common/BaseController.cs | 8 --- YLErpWeb/Controllers/RiskRuleController.cs | 62 +++++++++---------- 3 files changed, 65 insertions(+), 41 deletions(-) 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 index 3ab5fb65..68a57b0d 100644 --- 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 @@ -9,10 +9,42 @@ -- 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, NULL, 0, '', 0, NULL, NULL, NULL, NULL); +(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); +(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/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 55ba98e9..bbb5a6fb 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 @@ -571,7 +571,7 @@ namespace YLErp.Web.Controllers #region Trade Types [HttpGet("trade-types")] - [MyAuthorize("风控应用查看")] + [MyAuthorize("风险控制-风控应用查看")] public JsonResult GetTradeTypes() { try @@ -600,7 +600,7 @@ namespace YLErp.Web.Controllers #region Audit Log [HttpGet("risk-audit-logs")] - [MyAuthorize("风控日志查看")] + [MyAuthorize("风险控制-风控日志查看")] public JsonResult QueryRiskAuditLogs(QueryRiskAuditLogReq req) { try @@ -621,7 +621,7 @@ namespace YLErp.Web.Controllers } [HttpGet("risk-audit-logs/{id}")] - [MyAuthorize("风控日志查看")] + [MyAuthorize("风险控制-风控日志查看")] public JsonResult GetRiskAuditLogDetail(long id) { try @@ -642,7 +642,7 @@ namespace YLErp.Web.Controllers } [HttpGet("risk-audit-logs/export")] - [MyAuthorize("风控日志导出")] + [MyAuthorize("风险控制-风控日志导出")] public IActionResult ExportRiskAuditLogs(QueryRiskAuditLogReq req) { try From f78a5bdc2a04b5c76e546011e8b79d4397938491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=B9=E5=B3=B0?= Date: Thu, 2 Jul 2026 15:54:33 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E6=9F=A5=E8=AF=A2=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RiskEngine/Dto/QueryRiskAuditLogReq.cs | 3 +++ YLErpDAL/Modules/RiskEngine/RiskRuleService.cs | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) 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/RiskRuleService.cs b/YLErpDAL/Modules/RiskEngine/RiskRuleService.cs index 7e79f074..08421a07 100644 --- a/YLErpDAL/Modules/RiskEngine/RiskRuleService.cs +++ b/YLErpDAL/Modules/RiskEngine/RiskRuleService.cs @@ -1461,11 +1461,27 @@ 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.Date);