merge: 合并 feature/p132_74-risk-engine 最新改动到 glms/feature/1.4.2
合并风控引擎分支最新提交(风控超时校验SQL、标的/合约类型传参、 UnderlyingAssetClass 字段、缓存刷新与异步逻辑优化等),无冲突。
This commit is contained in:
@@ -66,5 +66,8 @@ namespace YLErp.DBModels
|
||||
|
||||
[NotMapped]
|
||||
public List<string> ApprovalRuleIds { get; set; } = new List<string>();
|
||||
|
||||
[NotMapped]
|
||||
public QuotaTrialStatusEnum? OldRiskTrialStatus { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
-- 新风控二次审批确认有效期配置
|
||||
-- 幂等:已存在则不重复插入
|
||||
INSERT INTO appconfig
|
||||
(
|
||||
PGroup,
|
||||
PName,
|
||||
PValue,
|
||||
PType,
|
||||
Remark,
|
||||
CreateTime,
|
||||
OptDate
|
||||
)
|
||||
SELECT
|
||||
'ProjectConfig',
|
||||
'Trade.RiskWarningConfirmExpireSeconds',
|
||||
'300',
|
||||
'int',
|
||||
'新风控二次审批确认有效期(秒),超过后需重新校验',
|
||||
NOW(),
|
||||
NOW()
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS
|
||||
(
|
||||
SELECT 1
|
||||
FROM appconfig
|
||||
WHERE PGroup = 'ProjectConfig'
|
||||
AND PName = 'Trade.RiskWarningConfirmExpireSeconds'
|
||||
);
|
||||
@@ -1,4 +1,4 @@
|
||||
using BaseOUDAL;
|
||||
using BaseOUDAL;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using YLErp.Enums;
|
||||
|
||||
@@ -33,6 +33,7 @@ namespace YLErp.Model
|
||||
this.AvailableForClient = obj.AvailableForClient;
|
||||
this.Remark = obj.Remark;
|
||||
this.TrialSource = obj.TrialSource;
|
||||
this.OldRiskTrialStatus = obj.OldRiskTrialStatus;
|
||||
this.OptId = obj.OptId;
|
||||
this.OptName = obj.OptName;
|
||||
this.OptDate = obj.OptDate;
|
||||
|
||||
@@ -519,7 +519,9 @@ namespace YLErp.Modules.RiskEngine
|
||||
/// </summary>
|
||||
private List<RiskRule> LoadRulesFromDb()
|
||||
{
|
||||
var rules = DbContext.glms_risk_rule
|
||||
using var dbContext = DbContextFactory.GetYLDbContext();
|
||||
|
||||
var rules = dbContext.glms_risk_rule
|
||||
.AsNoTracking()
|
||||
.OrderByDescending(r => r.UpdateDate ?? r.OptDate)
|
||||
.Select(r => new RiskRule
|
||||
@@ -736,8 +738,8 @@ namespace YLErp.Modules.RiskEngine
|
||||
//{
|
||||
// Id = 1000014,
|
||||
// RuleName = "非债券类价格偏离(本地)",
|
||||
// RuleText = "取值字段:通过 DbContext.swap_position 按 TradeId 取 PosiGrossPrice,对应普通收益互换页面填写的期初标的交割全价%,库内为 1 左右原值;通过 DbContext.eod_stock_price / eod_commodity_future_price 按当前交易标的和交易日前日期取上一日收盘价 ClosePrice。计算逻辑:按 ABS(PosiGrossPrice×100-ClosePrice) 计算绝对价差,价差大于 5 时触发审批。",
|
||||
// RuleExpr = "Math.Abs(DbContext.swap_position.First(p => p.SwapTradeId == TradeId).PosiGrossPrice * 100m - Convert.ToDecimal((DbContext.eod_stock_price.Where(e => e.UnderlyingCode == DbContext.trade.First(t => t.id == TradeId).UnderlyingCode && e.ValueDate < DbContext.trade.First(t => t.id == TradeId).TradeDate.Value.Date).OrderByDescending(e => e.ValueDate).Select(e => (double?)e.ClosePrice).FirstOrDefault() ?? DbContext.eod_commodity_future_price.Where(e => e.UnderlyingCode == DbContext.trade.First(t => t.id == TradeId).UnderlyingCode && e.ValueDate < DbContext.trade.First(t => t.id == TradeId).TradeDate.Value.Date).OrderByDescending(e => e.ValueDate).Select(e => (double?)e.ClosePrice).FirstOrDefault()).Value)) > 5m",
|
||||
// RuleText = "取值字段:通过 DbContext.swap_position 按 TradeId 取 PosiGrossPrice,对应普通收益互换页面填写的期初标的价格,库内为 1 左右原值;通过 DbContext.eod_commodity_future_price 按当前交易标的和交易日前日期取上一日收盘价 ClosePrice。计算逻辑:按 ABS(PosiGrossPrice×100-ClosePrice) 计算绝对价差,价差大于 5 时触发审批。",
|
||||
// RuleExpr = "Math.Abs(DbContext.swap_position.First(p => p.SwapTradeId == TradeId).PosiGrossPrice * 100m - Convert.ToDecimal(DbContext.eod_commodity_future_price.Where(e => e.UnderlyingCode == DbContext.trade.First(t => t.id == TradeId).UnderlyingCode && e.ValueDate < DbContext.trade.First(t => t.id == TradeId).TradeDate.Value.Date).OrderByDescending(e => e.ValueDate).First().ClosePrice)) > 5m",
|
||||
// Version = 1,
|
||||
// Status = RiskRuleStatus.Active,
|
||||
// OptId = 0,
|
||||
@@ -752,8 +754,8 @@ namespace YLErp.Modules.RiskEngine
|
||||
//{
|
||||
// Id = 1000015,
|
||||
// RuleName = "单一交易对手累计标的数量超阈值(本地)",
|
||||
// RuleText = "取值字段:通过 DbContext.trade 按 TradeId 取当前交易对手 ClientId,再查询同一交易对手存续/审批中交易的去重标的数量。计算逻辑:同一交易对手累计标的数量超过 10 个时触发审批。",
|
||||
// RuleExpr = "DbContext.trade.Where(t => t.ValidState != \"InValid\" && t.ClientId == DbContext.trade.First(x => x.id == TradeId).ClientId && t.ParentTradeId == 0 && (ConsTrade.NeedMarginTradeStatusList.Contains(t.TradeStatus) || t.TradeStatus == \"审批中\")).Select(t => t.UnderlyingId).Distinct().Count() > 10",
|
||||
// RuleText = "取值字段:通过 DbContext.trade 按 TradeId 取当前交易对手 ClientId,再查询同一交易对手存续/审批中交易对应的 swap_position.UnderlyingCode 去重数量。计算逻辑:同一交易对手累计标的数量超过 10 个时触发审批。",
|
||||
// RuleExpr= DbContext.swap_position.Where(p => !string.IsNullOrEmpty(p.UnderlyingCode) && p.IsInitial && !p.Invalid && DbContext.trade.Any(t => t.id == p.SwapTradeId && t.ValidState != "InValid" && t.ClientId == DbContext.trade.First(x => x.id == TradeId).ClientId && t.ParentTradeId == 0 && (ConsTrade.NeedMarginTradeStatusList.Contains(t.TradeStatus) || t.TradeStatus == "审批中"))).Select(p => p.UnderlyingCode).Distinct().Count() > 10
|
||||
// Version = 1,
|
||||
// Status = RiskRuleStatus.Active,
|
||||
// OptId = 0,
|
||||
@@ -768,8 +770,8 @@ namespace YLErp.Modules.RiskEngine
|
||||
//{
|
||||
// Id = 1000016,
|
||||
// RuleName = "多头支付固定端利率偏离(本地)",
|
||||
// RuleText = "取值字段:通过 DbContext.trade 按 TradeId 取当前交易的 FixedRate,并结合 BuySell 判断多头方向。计算逻辑:当 BuySell 表示多头且 FixedRate 有值时,先以 2.5% 作为本地测试基准,若 ABS(FixedRate-0.025)/0.025×100% 大于 5%,则触发审批。",
|
||||
// RuleExpr = "DbContext.trade.First(t => t.id == TradeId).BuySell == \"Buy\" && DbContext.trade.First(t => t.id == TradeId).FixedRate.HasValue && Math.Abs((DbContext.trade.First(t => t.id == TradeId).FixedRate.Value - 0.025d) / 0.025d) * 100d > 5d",
|
||||
// RuleText = "取值字段:通过 DbContext.swap_position 按 TradeId 取利息端支付方向记录的 InterestRateDefault,对应互换交易-利息端-利率文本框数值;通过 DbContext.eod_commodity_future_price 按 FutureContractId=FR007(模型属性 UnderlyingCode)和交易日前日期取最近一条 ClosePrice。计算逻辑:按 ABS(InterestRateDefault-FR007) 计算利率差,差值小于 5% 时触发审批。",
|
||||
// RuleExpr = "Math.Abs(DbContext.swap_position.First(p => p.SwapTradeId == TradeId && p.InterestDirection == 2).InterestRateDefault - Convert.ToDecimal(DbContext.eod_commodity_future_price.Where(e => e.UnderlyingCode == "FR007" && e.ValueDate < DbContext.trade.First(t => t.id == TradeId).TradeDate.Value.Date).OrderByDescending(e => e.ValueDate).First().ClosePrice)) < 0.05m",
|
||||
// Version = 1,
|
||||
// Status = RiskRuleStatus.Active,
|
||||
// OptId = 0,
|
||||
@@ -851,7 +853,9 @@ namespace YLErp.Modules.RiskEngine
|
||||
|
||||
private List<RiskRuleApplication> LoadApplicationsFromDb()
|
||||
{
|
||||
var applications = DbContext.glms_risk_rule_application
|
||||
using var dbContext = DbContextFactory.GetYLDbContext();
|
||||
|
||||
var applications = dbContext.glms_risk_rule_application
|
||||
.AsNoTracking()
|
||||
.OrderByDescending(a => a.UpdateDate ?? a.OptDate)
|
||||
.Select(a => new RiskRuleApplication
|
||||
@@ -992,22 +996,18 @@ namespace YLErp.Modules.RiskEngine
|
||||
|
||||
/// <summary>
|
||||
/// 读取交易的资产簿账户ID。
|
||||
/// 当前先按 BookId 取值;如果后续真实字段不是 BookId,再统一调整这里即可。
|
||||
/// </summary>
|
||||
private object GetTradeAssetBookId(YLErp.DBModels.trade trade)
|
||||
{
|
||||
var property = trade.GetType().GetProperty("BookId");
|
||||
return property?.GetValue(trade);
|
||||
return trade.AssetId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取交易的标的类型。
|
||||
/// 当前先按 UnderlyingInstrumentType 取值;如果后续真实字段名不同,再统一调整这里即可。
|
||||
/// </summary>
|
||||
private object GetTradeUnderlyingType(YLErp.DBModels.trade trade)
|
||||
{
|
||||
var property = trade.GetType().GetProperty("UnderlyingInstrumentType");
|
||||
return property?.GetValue(trade);
|
||||
return trade.UnderlyingAssetClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace YLErp.Modules.RiskEngine
|
||||
/// <summary>
|
||||
/// 应用状态。
|
||||
/// 约定:
|
||||
/// 1 = Active(已生效)
|
||||
/// 1 = Active(已启用)
|
||||
/// 2 = Disabled(已停用)
|
||||
/// 3 = Deleted(已删除)
|
||||
/// 在实际执行时,通常只加载 Active 状态的应用配置。
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using BaseOUDAL;
|
||||
using Newtonsoft.Json;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text.RegularExpressions;
|
||||
using YLErp.BLL;
|
||||
using YLErp.DBModels;
|
||||
using YLErp.Modules.RiskEngine.Dto;
|
||||
@@ -113,7 +115,7 @@ using YLErp.Modules.RiskEngine.Dto;
|
||||
ValidateTriggerPoints(triggerPoints) 触发时点校验(5 个合法时点)
|
||||
ValidateScopeFields(req) Scope 字段校验(全局互斥 + ID 格式校验)
|
||||
ValidateIdList(idList, fieldName) ID 列表格式校验
|
||||
TryRefreshCache() 安全调用 RefreshCache(失败仅记日志)
|
||||
RefreshOneRuleCache(ruleId) 单条规则缓存刷新(规则变更后调用)
|
||||
GetRuleOrThrow / GetApplicationOrThrow / GetVariableOrThrow 实体获取快捷方法
|
||||
|
||||
【关键设计决策】
|
||||
@@ -124,7 +126,7 @@ using YLErp.Modules.RiskEngine.Dto;
|
||||
5. ConditionJson 校验:变量存在性(按 VariableId)+ 操作符合法性(按 DataType 映射)+ 类型匹配 + 阈值变量引用
|
||||
6. RuleExpr:自由文本模式下前端直接编辑,后端做基础语法校验(括号匹配 + 变量引用校验)
|
||||
7. Scope 字段:逗号分隔字符串存储,全局适用时不允许指定其他维度
|
||||
8. 缓存刷新:写操作后调用 TryRefreshCache(),失败仅记日志不影响操作结果
|
||||
8. 缓存刷新:规则变更后调用 RefreshOneRuleCache(ruleId),应用变更后调用 RefreshApplication()
|
||||
9. 批量操作:单事务批量,全部成功或全部失败
|
||||
10. 变量缓存:5 分钟本地 HashSet<string> 缓存,CRUD 后 InvalidateVariableCache()
|
||||
11. 审计日志:16 种操作类型,CRUD + 审计日志同一事务,SnapshotData 存储版本快照
|
||||
@@ -172,7 +174,7 @@ using YLErp.Modules.RiskEngine.Dto;
|
||||
|
||||
【注意事项】
|
||||
1. RiskEngineService 由另一个团队开发实现,本服务通过 GetInstance() 获取单例引用
|
||||
2. 所有写操作后必须调用 TryRefreshCache(),确保引擎缓存与数据库一致
|
||||
2. 规则变更后调用 RefreshOneRuleCache(ruleId),应用变更后调用 RefreshApplication(),变量变更不触发引擎缓存刷新
|
||||
3. 变量删除为硬删除(物理删除),规则/应用删除为软删除(Status=Deleted)
|
||||
4. ExportAuditLogs 当前为占位实现,Excel 导出功能待后续迭代
|
||||
5. VariableExpr 当前仅做基础长度校验(≤10000),完整编译校验待引入 Roslyn 库
|
||||
@@ -539,23 +541,44 @@ namespace YLErp.Modules.RiskEngine
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 校验规则 ID 列表是否全部 Active
|
||||
/// 校验规则状态可用性并确保编译缓存就绪。
|
||||
/// 返回不可用规则信息列表,列表为空表示全部通过。
|
||||
/// 规则不可用的情况:已删除、已停用、编译缓存缺失且刷新失败。
|
||||
/// </summary>
|
||||
private void ValidateRuleIdsActive(string ruleIds)
|
||||
private List<string> ValidateAndEnsureRuleCache(string ruleIds)
|
||||
{
|
||||
var errors = new List<string>();
|
||||
var ids = ParseRuleIds(ruleIds);
|
||||
var rules = DbContext.glms_risk_rule
|
||||
.Where(r => ids.Contains(r.id) && r.Status != RiskRuleStatus.Deleted)
|
||||
.ToList();
|
||||
|
||||
if (rules.Count != ids.Count)
|
||||
throw new ServiceException("部分关联规则不存在或已删除");
|
||||
{
|
||||
var missingIds = ids.Except(rules.Select(r => (long)r.id)).ToList();
|
||||
foreach (var id in missingIds)
|
||||
errors.Add($"规则ID {id} 不存在或已删除");
|
||||
return errors;
|
||||
}
|
||||
|
||||
foreach (var rule in rules)
|
||||
{
|
||||
if (rule.Status == RiskRuleStatus.Disabled)
|
||||
throw new ServiceException($"关联规则 '{rule.RuleName}' 已停用,无法创建/启用应用配置");
|
||||
{
|
||||
errors.Add($"规则 '{rule.RuleName}' 已停用");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 检查编译缓存,未命中则刷新
|
||||
if (!RuleCompiledCache.TryGet(rule.id.ToString(), out _))
|
||||
{
|
||||
var result = RiskEngineService.GetInstance().RefreshOneRuleCache(rule.id);
|
||||
if (!result.Success)
|
||||
errors.Add($"规则 '{rule.RuleName}' 编译失败:{result.ErrorMessage}");
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -850,7 +873,7 @@ namespace YLErp.Modules.RiskEngine
|
||||
WriteAuditLog("RULE_DELETE", "RULE", ruleId, rule.RuleName, "删除规则");
|
||||
DbContext.SaveChanges();
|
||||
|
||||
TryRefreshCache();
|
||||
RiskEngineService.GetInstance().RefreshOneRuleCache(ruleId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -862,6 +885,10 @@ namespace YLErp.Modules.RiskEngine
|
||||
if (rule == null)
|
||||
throw new ServiceException("仅已停用的规则可以启用");
|
||||
|
||||
var compileResult = RuleCompiler.ValidateAndCompileFormula(ruleId, rule.RuleExpr);
|
||||
if (!compileResult.Success)
|
||||
throw new ServiceException($"规则表达式编译失败:{compileResult.ErrorMessage}");
|
||||
|
||||
rule.Status = RiskRuleStatus.Active;
|
||||
rule.UpdateOptId = UserId;
|
||||
rule.UpdateOptName = UserName;
|
||||
@@ -870,7 +897,7 @@ namespace YLErp.Modules.RiskEngine
|
||||
WriteAuditLog("RULE_ENABLE", "RULE", ruleId, rule.RuleName, "启用规则");
|
||||
DbContext.SaveChanges();
|
||||
|
||||
TryRefreshCache();
|
||||
RiskEngineService.GetInstance().RefreshOneRuleCache(ruleId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -880,7 +907,7 @@ namespace YLErp.Modules.RiskEngine
|
||||
{
|
||||
var rule = DbContext.glms_risk_rule.FirstOrDefault(r => r.id == ruleId && r.Status == RiskRuleStatus.Active);
|
||||
if (rule == null)
|
||||
throw new ServiceException("仅已生效的规则可以停用");
|
||||
throw new ServiceException("仅已启用的规则可以停用");
|
||||
|
||||
rule.Status = RiskRuleStatus.Disabled;
|
||||
rule.UpdateOptId = UserId;
|
||||
@@ -890,7 +917,7 @@ namespace YLErp.Modules.RiskEngine
|
||||
WriteAuditLog("RULE_DISABLE", "RULE", ruleId, rule.RuleName, "停用规则");
|
||||
DbContext.SaveChanges();
|
||||
|
||||
TryRefreshCache();
|
||||
RiskEngineService.GetInstance().RefreshOneRuleCache(ruleId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -966,7 +993,10 @@ namespace YLErp.Modules.RiskEngine
|
||||
}
|
||||
|
||||
DbContext.SaveChanges();
|
||||
TryRefreshCache();
|
||||
foreach (var ruleId in ruleIds)
|
||||
{
|
||||
RiskEngineService.GetInstance().RefreshOneRuleCache(ruleId);
|
||||
}
|
||||
|
||||
return new BatchOperationResult
|
||||
{
|
||||
@@ -1140,7 +1170,9 @@ namespace YLErp.Modules.RiskEngine
|
||||
/// </summary>
|
||||
public RiskApplicationDetail CreateApplication(CreateRiskApplicationReq req)
|
||||
{
|
||||
ValidateRuleIdsActive(req.RuleIds);
|
||||
var errors = ValidateAndEnsureRuleCache(req.RuleIds);
|
||||
if (errors.Any())
|
||||
throw new ServiceException($"以下关联规则不可用:{string.Join(";", errors)}");
|
||||
ValidateTriggerPoints(req.TriggerPoints);
|
||||
ValidateScopeFields(req);
|
||||
|
||||
@@ -1201,7 +1233,11 @@ namespace YLErp.Modules.RiskEngine
|
||||
throw new ServiceException("应用配置已被其他用户修改,请重新加载后再编辑");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(req.RuleIds))
|
||||
ValidateRuleIdsActive(req.RuleIds);
|
||||
{
|
||||
var errors = ValidateAndEnsureRuleCache(req.RuleIds);
|
||||
if (errors.Any())
|
||||
throw new ServiceException($"以下关联规则不可用:{string.Join(";", errors)}");
|
||||
}
|
||||
|
||||
ValidateTriggerPoints(req.TriggerPoints);
|
||||
var scopeReq = new CreateRiskApplicationReq
|
||||
@@ -1266,7 +1302,9 @@ namespace YLErp.Modules.RiskEngine
|
||||
if (app == null)
|
||||
throw new ServiceException("仅已停用的应用配置可以启用");
|
||||
|
||||
ValidateRuleIdsActive(app.RuleIds);
|
||||
var errors = ValidateAndEnsureRuleCache(app.RuleIds);
|
||||
if (errors.Any())
|
||||
throw new ServiceException($"以下关联规则不可用:{string.Join(";", errors)}");
|
||||
|
||||
app.Status = RiskRuleStatus.Active;
|
||||
app.UpdateOptId = UserId;
|
||||
@@ -1286,7 +1324,7 @@ namespace YLErp.Modules.RiskEngine
|
||||
{
|
||||
var app = DbContext.glms_risk_rule_application.FirstOrDefault(a => a.id == applicationId && a.Status == RiskRuleStatus.Active);
|
||||
if (app == null)
|
||||
throw new ServiceException("仅已生效的应用配置可以停用");
|
||||
throw new ServiceException("仅已启用的应用配置可以停用");
|
||||
|
||||
app.Status = RiskRuleStatus.Disabled;
|
||||
app.UpdateOptId = UserId;
|
||||
@@ -1304,20 +1342,41 @@ namespace YLErp.Modules.RiskEngine
|
||||
/// </summary>
|
||||
public BatchOperationResult BatchEnableApplications(List<long> applicationIds)
|
||||
{
|
||||
_logger.Info($"[批量启用] 开始 - 传入应用数: {applicationIds?.Count ?? 0}, IDs: {string.Join(",", applicationIds ?? new List<long>())}");
|
||||
|
||||
var apps = DbContext.glms_risk_rule_application
|
||||
.Where(a => applicationIds.Contains(a.id) && a.Status == RiskRuleStatus.Disabled)
|
||||
.ToList();
|
||||
|
||||
_logger.Info($"[批量启用] DB查询完成 - 匹配到 {apps.Count} 条已停用应用");
|
||||
|
||||
if (apps.Count != applicationIds.Count)
|
||||
throw new ServiceException("部分应用配置不存在或当前状态不允许启用");
|
||||
|
||||
var allErrors = new List<string>();
|
||||
foreach (var app in apps)
|
||||
{
|
||||
ValidateRuleIdsActive(app.RuleIds);
|
||||
_logger.Info($"[批量启用] 校验规则 - 应用ID: {app.id}, RuleIds: {app.RuleIds}");
|
||||
var errors = ValidateAndEnsureRuleCache(app.RuleIds);
|
||||
_logger.Info($"[批量启用] 规则校验结果 - 应用ID: {app.id}, Errors: {(errors.Any() ? string.Join(";", errors) : "无")}");
|
||||
if (errors.Any())
|
||||
allErrors.Add($"应用 '{app.Description}':{string.Join(";", errors)}");
|
||||
}
|
||||
|
||||
if (allErrors.Any())
|
||||
{
|
||||
return new BatchOperationResult
|
||||
{
|
||||
Success = false,
|
||||
TotalCount = applicationIds.Count,
|
||||
SuccessCount = 0,
|
||||
ErrorMessage = string.Join(";", allErrors)
|
||||
};
|
||||
}
|
||||
|
||||
foreach (var app in apps)
|
||||
{
|
||||
_logger.Info($"[批量启用] 写入状态 - 应用ID: {app.id}");
|
||||
app.Status = RiskRuleStatus.Active;
|
||||
app.UpdateOptId = UserId;
|
||||
app.UpdateOptName = UserName;
|
||||
@@ -1326,8 +1385,11 @@ namespace YLErp.Modules.RiskEngine
|
||||
WriteAuditLog("APP_BATCH_ENABLE", "APPLICATION", app.id, ResolveRuleNames(app.RuleIds), "批量启用应用配置");
|
||||
}
|
||||
|
||||
_logger.Info("[批量启用] 保存数据库...");
|
||||
DbContext.SaveChanges();
|
||||
_logger.Info("[批量启用] 刷新应用缓存...");
|
||||
RiskEngineService.GetInstance().RefreshApplication();
|
||||
_logger.Info("[批量启用] 完成");
|
||||
|
||||
return new BatchOperationResult
|
||||
{
|
||||
@@ -1342,15 +1404,20 @@ namespace YLErp.Modules.RiskEngine
|
||||
/// </summary>
|
||||
public BatchOperationResult BatchDisableApplications(List<long> applicationIds)
|
||||
{
|
||||
_logger.Info($"[批量停用] 开始 - 传入应用数: {applicationIds?.Count ?? 0}, IDs: {string.Join(",", applicationIds ?? new List<long>())}");
|
||||
|
||||
var apps = DbContext.glms_risk_rule_application
|
||||
.Where(a => applicationIds.Contains(a.id) && a.Status == RiskRuleStatus.Active)
|
||||
.ToList();
|
||||
|
||||
_logger.Info($"[批量停用] DB查询完成 - 匹配到 {apps.Count} 条已启用应用");
|
||||
|
||||
if (apps.Count != applicationIds.Count)
|
||||
throw new ServiceException("部分应用配置不存在或当前状态不允许停用");
|
||||
|
||||
foreach (var app in apps)
|
||||
{
|
||||
_logger.Info($"[批量停用] 写入状态 - 应用ID: {app.id}");
|
||||
app.Status = RiskRuleStatus.Disabled;
|
||||
app.UpdateOptId = UserId;
|
||||
app.UpdateOptName = UserName;
|
||||
@@ -1359,8 +1426,11 @@ namespace YLErp.Modules.RiskEngine
|
||||
WriteAuditLog("APP_BATCH_DISABLE", "APPLICATION", app.id, ResolveRuleNames(app.RuleIds), "批量停用应用配置");
|
||||
}
|
||||
|
||||
_logger.Info("[批量停用] 保存数据库...");
|
||||
DbContext.SaveChanges();
|
||||
_logger.Info("[批量停用] 刷新应用缓存...");
|
||||
RiskEngineService.GetInstance().RefreshApplication();
|
||||
_logger.Info("[批量停用] 完成");
|
||||
|
||||
return new BatchOperationResult
|
||||
{
|
||||
@@ -1372,6 +1442,27 @@ namespace YLErp.Modules.RiskEngine
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 查询 ConditionJson 中引用了指定变量 ID 的规则(仅结构化模式)
|
||||
/// 精确匹配 "VariableId":{id} 或 "ThresholdVariableId":{id},\b 防止 id=1 误匹配 id=10
|
||||
/// </summary>
|
||||
private List<glms_risk_rule> GetRulesByVariableId(long variableId)
|
||||
{
|
||||
var allRules = DbContext.glms_risk_rule
|
||||
.Where(r => r.Status != RiskRuleStatus.Deleted && r.ConditionJson != null)
|
||||
.ToList();
|
||||
|
||||
if (allRules.Count == 0) return allRules;
|
||||
|
||||
var idPattern = $@"""VariableId""\s*:\s*{variableId}\b";
|
||||
var thresholdPattern = $@"""ThresholdVariableId""\s*:\s*{variableId}\b";
|
||||
|
||||
return allRules.Where(r =>
|
||||
Regex.IsMatch(r.ConditionJson, idPattern) ||
|
||||
Regex.IsMatch(r.ConditionJson, thresholdPattern)
|
||||
).ToList();
|
||||
}
|
||||
|
||||
#region Variable Management
|
||||
|
||||
/// <summary>
|
||||
@@ -1498,7 +1589,6 @@ namespace YLErp.Modules.RiskEngine
|
||||
}
|
||||
|
||||
InvalidateVariableCache();
|
||||
TryRefreshCache();
|
||||
|
||||
return GetVariableDetail(entity.id);
|
||||
}
|
||||
@@ -1520,11 +1610,8 @@ namespace YLErp.Modules.RiskEngine
|
||||
|
||||
if (req.DataType != variable.DataType)
|
||||
{
|
||||
var varExpr = variable.VariableExpr;
|
||||
var activeRefCount = DbContext.glms_risk_rule
|
||||
.Count(r => r.Status == RiskRuleStatus.Active &&
|
||||
((r.ConditionJson != null && r.ConditionJson.Contains(variable.id.ToString())) ||
|
||||
(r.RuleExpr != null && varExpr != null && r.RuleExpr.Contains(varExpr))));
|
||||
var activeRefCount = GetRulesByVariableId(variableId)
|
||||
.Count(r => r.Status == RiskRuleStatus.Active);
|
||||
if (activeRefCount > 0)
|
||||
throw new ServiceException($"该变量被 {activeRefCount} 个生效中的规则引用,无法修改数据类型");
|
||||
}
|
||||
@@ -1548,9 +1635,9 @@ namespace YLErp.Modules.RiskEngine
|
||||
|
||||
if (variableExprChanged)
|
||||
{
|
||||
// 编译校验:变量表达式变更后,需验证所有级联更新的规则表达式可编译
|
||||
var affectedRules = DbContext.glms_risk_rule
|
||||
.Where(r => r.RuleExpr != null && r.RuleExpr.Contains(oldVariableExpr))
|
||||
// 结构化模式:通过 ConditionJson 中的 VariableId 找到受影响的规则
|
||||
var affectedRules = GetRulesByVariableId(variableId)
|
||||
.Where(r => r.RuleExpr != null)
|
||||
.ToList();
|
||||
|
||||
var compileTasks = affectedRules.Select(r =>
|
||||
@@ -1579,11 +1666,9 @@ namespace YLErp.Modules.RiskEngine
|
||||
|
||||
WriteAuditLog("VAR_UPDATE", "VARIABLE", variableId, req.VariableName, $"修改变量:{variable.VariableName}");
|
||||
|
||||
foreach (var rule in affectedRules)
|
||||
{
|
||||
WriteAuditLog("VAR_UPDATE_CASCADE", "RULE", rule.id, rule.RuleName,
|
||||
$"变量 [{variable.VariableName}] VariableExpr 变更,级联更新规则 RuleExpr");
|
||||
}
|
||||
var cascadedRuleIds = affectedRules.Select(r => r.id.ToString()).ToList();
|
||||
WriteAuditLog("VAR_UPDATE_CASCADE", "VARIABLE", variableId, req.VariableName,
|
||||
$"变量 [{variable.VariableName}] VariableExpr 变更,级联更新规则 {string.Join("、", cascadedRuleIds)}");
|
||||
|
||||
DbContext.SaveChanges();
|
||||
transaction.Commit();
|
||||
@@ -1618,11 +1703,8 @@ namespace YLErp.Modules.RiskEngine
|
||||
{
|
||||
var variable = GetVariableOrThrow(variableId);
|
||||
|
||||
var varExpr = variable.VariableExpr;
|
||||
var activeRefCount = DbContext.glms_risk_rule
|
||||
.Count(r => r.Status == RiskRuleStatus.Active &&
|
||||
((r.ConditionJson != null && r.ConditionJson.Contains(variable.id.ToString())) ||
|
||||
(r.RuleExpr != null && varExpr != null && r.RuleExpr.Contains(varExpr))));
|
||||
var activeRefCount = GetRulesByVariableId(variableId)
|
||||
.Count(r => r.Status == RiskRuleStatus.Active);
|
||||
if (activeRefCount > 0)
|
||||
throw new ServiceException($"该变量被 {activeRefCount} 个生效中的规则引用,无法删除");
|
||||
|
||||
@@ -1632,7 +1714,6 @@ namespace YLErp.Modules.RiskEngine
|
||||
DbContext.SaveChanges();
|
||||
|
||||
InvalidateVariableCache();
|
||||
TryRefreshCache();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -4470,11 +4470,16 @@ namespace YLErp.Modules.RiskModule
|
||||
|
||||
public bool QuotaCheck(ref TradeOpenResult res, bool ignoreRiskWarning, IEnumerable<string> ignoreRiskRuleIds = null)
|
||||
{
|
||||
if (res == null || res.Trade == null)
|
||||
if (res == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(res));
|
||||
}
|
||||
|
||||
if (res.Trade == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(res.Trade));
|
||||
}
|
||||
|
||||
var tradeId = (res.Trade.ParentTradeId == 0 || res.Trade.IsGroup != 0) ? res.Trade.id : res.Trade.ParentTradeId;
|
||||
var tradeNumber = DbContext.trade.Where(O => O.id == tradeId).Select(O => O.TradeNumber).FirstOrDefault();
|
||||
var trialService = new QuotaMonitorService(this);
|
||||
@@ -4518,8 +4523,9 @@ namespace YLErp.Modules.RiskModule
|
||||
var isRiskApprovalWarning = quotaObj.TrialStatus == QuotaTrialStatusEnum.RiskWarning
|
||||
&& !string.IsNullOrWhiteSpace(quotaObj.RiskWarningDetails)
|
||||
&& (quotaObj.ApprovalRuleIds?.Any() ?? false);
|
||||
//当前为老风控特批,不是新风控需审批
|
||||
res.OldRiskNeedSpecialApproval = quotaObj.TrialStatus == QuotaTrialStatusEnum.Warning;
|
||||
//老风控试算不通过时,延用master逻辑进入交易特批/二次处理;新风控需审批由RiskWarning单独处理
|
||||
res.OldRiskNeedSpecialApproval = quotaObj.OldRiskTrialStatus.HasValue
|
||||
&& quotaObj.OldRiskTrialStatus.Value != QuotaTrialStatusEnum.Success;
|
||||
if (isRiskApprovalWarning)
|
||||
{
|
||||
var currentApprovalRuleIds = quotaObj.ApprovalRuleIds ?? new List<string>();
|
||||
@@ -5148,6 +5154,7 @@ namespace YLErp.Modules.RiskModule
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (quotaWarningStatus && riskWarningStatus && fundStatus && quotaStatus)
|
||||
{
|
||||
result.TrialStatus = QuotaTrialStatusEnum.Success;
|
||||
@@ -5172,6 +5179,7 @@ namespace YLErp.Modules.RiskModule
|
||||
result.QuotaWarningDetails = quotaWarningMsg ?? "";
|
||||
result.AvailableForClient = availableMsg ?? "";
|
||||
result.TrialSource = trialSource;
|
||||
result.OldRiskTrialStatus = result.TrialStatus;
|
||||
_logger.Info($"[限额试算] 试算完成 - tradeId: {tradeId}, TrialStatus: {result.TrialStatus}, FundCheck: {fundStatus}, QuotaCheck: {quotaStatus}");
|
||||
|
||||
// ===== 新风控引擎接入点(设计文档 4.6.1) =====
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Qdp.Foundation.Utilities;
|
||||
using System.Threading.Tasks;
|
||||
using YLErp.DBModels;
|
||||
using YLErp.Modules.RiskEngine;
|
||||
using YLErp.Modules.RiskEngine.Dto;
|
||||
@@ -11,17 +12,19 @@ namespace YLErp.Web.Controllers
|
||||
{
|
||||
private readonly IYcLogger _logger = LogFactory.GetLogger("RiskRuleController");
|
||||
|
||||
private RiskRuleService GetRiskRuleService() => new RiskRuleService(CurUser);
|
||||
|
||||
#region Rule Management
|
||||
|
||||
[HttpGet("risk-rules")]
|
||||
[MyAuthorize("风险控制-风控规则查看")]
|
||||
/// <summary>查询风控规则列表(分页)</summary>
|
||||
public JsonResult QueryRiskRules(QueryRiskRuleReq req)
|
||||
public async Task<JsonResult> QueryRiskRules(QueryRiskRuleReq req)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var result = service.QueryRuleList(req);
|
||||
var service = GetRiskRuleService();
|
||||
var result = await Task.Run(() => service.QueryRuleList(req));
|
||||
return Json(new { success = true, data = result });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -38,12 +41,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpGet("risk-rules/{id}")]
|
||||
[MyAuthorize("风险控制-风控规则查看")]
|
||||
/// <summary>获取风控规则详情</summary>
|
||||
public JsonResult GetRiskRule(long id)
|
||||
public async Task<JsonResult> GetRiskRule(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var result = service.GetRuleDetail(id);
|
||||
var service = GetRiskRuleService();
|
||||
var result = await Task.Run(() => service.GetRuleDetail(id));
|
||||
return Json(new { success = true, data = result });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -60,12 +63,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpGet("risk-rules/{id}/versions")]
|
||||
[MyAuthorize("风险控制-风控规则查看")]
|
||||
/// <summary>获取风控规则版本历史</summary>
|
||||
public JsonResult GetRiskRuleVersions(long id)
|
||||
public async Task<JsonResult> GetRiskRuleVersions(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var result = service.GetRuleVersions(id);
|
||||
var service = GetRiskRuleService();
|
||||
var result = await Task.Run(() => service.GetRuleVersions(id));
|
||||
return Json(new { success = true, data = result });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -82,12 +85,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpPost("risk-rules")]
|
||||
[MyAuthorize("风险控制-风控规则新增")]
|
||||
/// <summary>创建风控规则</summary>
|
||||
public JsonResult CreateRiskRule([FromBody] CreateRiskRuleReq req)
|
||||
public async Task<JsonResult> CreateRiskRule([FromBody] CreateRiskRuleReq req)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var result = service.CreateRule(req);
|
||||
var service = GetRiskRuleService();
|
||||
var result = await Task.Run(() => service.CreateRule(req));
|
||||
return Json(new { success = true, data = result });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -104,12 +107,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpPut("risk-rules/{id}")]
|
||||
[MyAuthorize("风险控制-风控规则编辑")]
|
||||
/// <summary>更新风控规则</summary>
|
||||
public JsonResult UpdateRiskRule(long id, [FromBody] UpdateRiskRuleReq req)
|
||||
public async Task<JsonResult> UpdateRiskRule(long id, [FromBody] UpdateRiskRuleReq req)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var result = service.UpdateRule(id, req);
|
||||
var service = GetRiskRuleService();
|
||||
var result = await Task.Run(() => service.UpdateRule(id, req));
|
||||
return Json(new { success = true, data = result });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -126,12 +129,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpDelete("risk-rules/{id}")]
|
||||
[MyAuthorize("风险控制-风控规则删除")]
|
||||
/// <summary>删除风控规则(软删除)</summary>
|
||||
public JsonResult DeleteRiskRule(long id)
|
||||
public async Task<JsonResult> DeleteRiskRule(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
service.DeleteRule(id);
|
||||
var service = GetRiskRuleService();
|
||||
await Task.Run(() => service.DeleteRule(id));
|
||||
return Json(new { success = true });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -148,12 +151,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpDelete("risk-rules/batch")]
|
||||
[MyAuthorize("风险控制-风控规则删除")]
|
||||
/// <summary>批量删除风控规则</summary>
|
||||
public JsonResult BatchDeleteRiskRules([FromBody] List<long> ids)
|
||||
public async Task<JsonResult> BatchDeleteRiskRules([FromBody] List<long> ids)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var result = service.BatchDeleteRules(ids);
|
||||
var service = GetRiskRuleService();
|
||||
var result = await Task.Run(() => service.BatchDeleteRules(ids));
|
||||
return Json(new { success = true, data = result });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -170,12 +173,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpPost("risk-rules/{id}/enable")]
|
||||
[MyAuthorize("风险控制-风控规则启停")]
|
||||
/// <summary>启用风控规则</summary>
|
||||
public JsonResult EnableRiskRule(long id)
|
||||
public async Task<JsonResult> EnableRiskRule(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
service.EnableRule(id);
|
||||
var service = GetRiskRuleService();
|
||||
await Task.Run(() => service.EnableRule(id));
|
||||
return Json(new { success = true });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -192,12 +195,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpPost("risk-rules/{id}/disable")]
|
||||
[MyAuthorize("风险控制-风控规则启停")]
|
||||
/// <summary>停用风控规则</summary>
|
||||
public JsonResult DisableRiskRule(long id)
|
||||
public async Task<JsonResult> DisableRiskRule(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
service.DisableRule(id);
|
||||
var service = GetRiskRuleService();
|
||||
await Task.Run(() => service.DisableRule(id));
|
||||
return Json(new { success = true });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -214,12 +217,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpGet("risk-rules/{id}/applications")]
|
||||
[MyAuthorize("风险控制-风控规则查看")]
|
||||
/// <summary>获取规则关联的应用配置列表</summary>
|
||||
public JsonResult GetRuleApplications(long id)
|
||||
public async Task<JsonResult> GetRuleApplications(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var result = service.GetRuleApplications(id);
|
||||
var service = GetRiskRuleService();
|
||||
var result = await Task.Run(() => service.GetRuleApplications(id));
|
||||
return Json(new { success = true, data = new { rows = result, total = result.Count, records = result.Count, page = 1 } });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -236,12 +239,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpGet("risk-rules/list")]
|
||||
[MyAuthorize("风险控制-风控规则查看")]
|
||||
/// <summary>获取所有启用规则列表(供下拉选择)</summary>
|
||||
public JsonResult GetAllRiskRules()
|
||||
public async Task<JsonResult> GetAllRiskRules()
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var result = service.GetAllRuleList();
|
||||
var service = GetRiskRuleService();
|
||||
var result = await Task.Run(() => service.GetAllRuleList());
|
||||
return Json(new { success = true, data = new { rows = result, total = result.Count, records = result.Count, page = 1 } });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -262,12 +265,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpGet("risk-applications")]
|
||||
[MyAuthorize("风险控制-风控应用查看")]
|
||||
/// <summary>查询应用配置列表(分页)</summary>
|
||||
public JsonResult QueryRiskApplications(QueryRiskApplicationReq req)
|
||||
public async Task<JsonResult> QueryRiskApplications(QueryRiskApplicationReq req)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var result = service.QueryApplicationList(req);
|
||||
var service = GetRiskRuleService();
|
||||
var result = await Task.Run(() => service.QueryApplicationList(req));
|
||||
return Json(new { success = true, data = result });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -284,12 +287,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpGet("risk-applications/{id}")]
|
||||
[MyAuthorize("风险控制-风控应用查看")]
|
||||
/// <summary>获取应用配置详情</summary>
|
||||
public JsonResult GetRiskApplication(long id)
|
||||
public async Task<JsonResult> GetRiskApplication(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var result = service.GetApplicationDetail(id);
|
||||
var service = GetRiskRuleService();
|
||||
var result = await Task.Run(() => service.GetApplicationDetail(id));
|
||||
return Json(new { success = true, data = result });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -306,12 +309,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpPost("risk-applications")]
|
||||
[MyAuthorize("风险控制-风控应用新增")]
|
||||
/// <summary>创建应用配置</summary>
|
||||
public JsonResult CreateRiskApplication([FromBody] CreateRiskApplicationReq req)
|
||||
public async Task<JsonResult> CreateRiskApplication([FromBody] CreateRiskApplicationReq req)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var result = service.CreateApplication(req);
|
||||
var service = GetRiskRuleService();
|
||||
var result = await Task.Run(() => service.CreateApplication(req));
|
||||
return Json(new { success = true, data = result });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -328,12 +331,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpPut("risk-applications/{id}")]
|
||||
[MyAuthorize("风险控制-风控应用编辑")]
|
||||
/// <summary>更新应用配置</summary>
|
||||
public JsonResult UpdateRiskApplication(long id, [FromBody] UpdateRiskApplicationReq req)
|
||||
public async Task<JsonResult> UpdateRiskApplication(long id, [FromBody] UpdateRiskApplicationReq req)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var result = service.UpdateApplication(id, req);
|
||||
var service = GetRiskRuleService();
|
||||
var result = await Task.Run(() => service.UpdateApplication(id, req));
|
||||
return Json(new { success = true, data = result });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -350,12 +353,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpDelete("risk-applications/{id}")]
|
||||
[MyAuthorize("风险控制-风控应用删除")]
|
||||
/// <summary>删除应用配置(软删除)</summary>
|
||||
public JsonResult DeleteRiskApplication(long id)
|
||||
public async Task<JsonResult> DeleteRiskApplication(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
service.DeleteApplication(id);
|
||||
var service = GetRiskRuleService();
|
||||
await Task.Run(() => service.DeleteApplication(id));
|
||||
return Json(new { success = true });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -372,12 +375,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpPost("risk-applications/{id}/enable")]
|
||||
[MyAuthorize("风险控制-风控应用启停")]
|
||||
/// <summary>启用应用配置</summary>
|
||||
public JsonResult EnableRiskApplication(long id)
|
||||
public async Task<JsonResult> EnableRiskApplication(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
service.EnableApplication(id);
|
||||
var service = GetRiskRuleService();
|
||||
await Task.Run(() => service.EnableApplication(id));
|
||||
return Json(new { success = true });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -394,12 +397,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpPost("risk-applications/{id}/disable")]
|
||||
[MyAuthorize("风险控制-风控应用启停")]
|
||||
/// <summary>停用应用配置</summary>
|
||||
public JsonResult DisableRiskApplication(long id)
|
||||
public async Task<JsonResult> DisableRiskApplication(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
service.DisableApplication(id);
|
||||
var service = GetRiskRuleService();
|
||||
await Task.Run(() => service.DisableApplication(id));
|
||||
return Json(new { success = true });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -416,12 +419,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpPost("risk-applications/batch-enable")]
|
||||
[MyAuthorize("风险控制-风控应用启停")]
|
||||
/// <summary>批量启用应用配置</summary>
|
||||
public JsonResult BatchEnableRiskApplications([FromBody] List<long> ids)
|
||||
public async Task<JsonResult> BatchEnableRiskApplications([FromBody] List<long> ids)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var result = service.BatchEnableApplications(ids);
|
||||
var service = GetRiskRuleService();
|
||||
var result = await Task.Run(() => service.BatchEnableApplications(ids));
|
||||
return Json(new { success = true, data = result });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -438,12 +441,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpPost("risk-applications/batch-disable")]
|
||||
[MyAuthorize("风险控制-风控应用启停")]
|
||||
/// <summary>批量停用应用配置</summary>
|
||||
public JsonResult BatchDisableRiskApplications([FromBody] List<long> ids)
|
||||
public async Task<JsonResult> BatchDisableRiskApplications([FromBody] List<long> ids)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var result = service.BatchDisableApplications(ids);
|
||||
var service = GetRiskRuleService();
|
||||
var result = await Task.Run(() => service.BatchDisableApplications(ids));
|
||||
return Json(new { success = true, data = result });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -464,12 +467,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpGet("risk-variables")]
|
||||
[MyAuthorize("风险控制-风控变量查看")]
|
||||
/// <summary>查询变量列表</summary>
|
||||
public JsonResult QueryRiskVariables(QueryRiskVariableReq req)
|
||||
public async Task<JsonResult> QueryRiskVariables(QueryRiskVariableReq req)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var result = service.QueryVariableList(req);
|
||||
var service = GetRiskRuleService();
|
||||
var result = await Task.Run(() => service.QueryVariableList(req));
|
||||
return Json(new { success = true, data = result });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -486,12 +489,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpGet("risk-variables/{id}")]
|
||||
[MyAuthorize("风险控制-风控变量查看")]
|
||||
/// <summary>获取变量详情</summary>
|
||||
public JsonResult GetRiskVariable(long id)
|
||||
public async Task<JsonResult> GetRiskVariable(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var result = service.GetVariableDetail(id);
|
||||
var service = GetRiskRuleService();
|
||||
var result = await Task.Run(() => service.GetVariableDetail(id));
|
||||
return Json(new { success = true, data = result });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -508,12 +511,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpGet("risk-variables/list")]
|
||||
[MyAuthorize("风险控制-风控变量查看")]
|
||||
/// <summary>获取所有变量列表(供下拉选择)</summary>
|
||||
public JsonResult GetAllRiskVariables()
|
||||
public async Task<JsonResult> GetAllRiskVariables()
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var result = service.GetAllVariableList();
|
||||
var service = GetRiskRuleService();
|
||||
var result = await Task.Run(() => service.GetAllVariableList());
|
||||
return Json(new { success = true, data = new { rows = result, total = result.Count, records = result.Count, page = 1 } });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -530,12 +533,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpPost("risk-variables")]
|
||||
[MyAuthorize("风险控制-风控变量新增")]
|
||||
/// <summary>创建变量</summary>
|
||||
public JsonResult CreateRiskVariable([FromBody] CreateRiskVariableReq req)
|
||||
public async Task<JsonResult> CreateRiskVariable([FromBody] CreateRiskVariableReq req)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var result = service.CreateVariable(req);
|
||||
var service = GetRiskRuleService();
|
||||
var result = await Task.Run(() => service.CreateVariable(req));
|
||||
return Json(new { success = true, data = result });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -552,12 +555,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpPut("risk-variables/{id}")]
|
||||
[MyAuthorize("风险控制-风控变量编辑")]
|
||||
/// <summary>更新变量(含级联更新引用规则的 RuleExpr)</summary>
|
||||
public JsonResult UpdateRiskVariable(long id, [FromBody] UpdateRiskVariableReq req)
|
||||
public async Task<JsonResult> UpdateRiskVariable(long id, [FromBody] UpdateRiskVariableReq req)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var result = service.UpdateVariable(id, req);
|
||||
var service = GetRiskRuleService();
|
||||
var result = await Task.Run(() => service.UpdateVariable(id, req));
|
||||
return Json(new { success = true, data = result });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -574,12 +577,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpDelete("risk-variables/{id}")]
|
||||
[MyAuthorize("风险控制-风控变量删除")]
|
||||
/// <summary>删除变量</summary>
|
||||
public JsonResult DeleteRiskVariable(long id)
|
||||
public async Task<JsonResult> DeleteRiskVariable(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
service.DeleteVariable(id);
|
||||
var service = GetRiskRuleService();
|
||||
await Task.Run(() => service.DeleteVariable(id));
|
||||
return Json(new { success = true });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -599,7 +602,7 @@ namespace YLErp.Web.Controllers
|
||||
|
||||
[HttpGet("trade-types")]
|
||||
[MyAuthorize("风险控制-风控应用查看")]
|
||||
/// <summary>获取合约类型列表</summary>
|
||||
/// <summary>获取合约类型列表(纯内存操作,无需异步)</summary>
|
||||
public JsonResult GetTradeTypes()
|
||||
{
|
||||
try
|
||||
@@ -630,12 +633,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpGet("risk-audit-logs")]
|
||||
[MyAuthorize("风险控制-风控日志查看")]
|
||||
/// <summary>查询风控操作日志列表(分页)</summary>
|
||||
public JsonResult QueryRiskAuditLogs(QueryRiskAuditLogReq req)
|
||||
public async Task<JsonResult> QueryRiskAuditLogs(QueryRiskAuditLogReq req)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var result = service.QueryAuditLogs(req);
|
||||
var service = GetRiskRuleService();
|
||||
var result = await Task.Run(() => service.QueryAuditLogs(req));
|
||||
return Json(new { success = true, data = result });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -652,12 +655,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpGet("risk-audit-logs/{id}")]
|
||||
[MyAuthorize("风险控制-风控日志查看")]
|
||||
/// <summary>获取风控操作日志详情</summary>
|
||||
public JsonResult GetRiskAuditLogDetail(long id)
|
||||
public async Task<JsonResult> GetRiskAuditLogDetail(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var result = service.GetAuditLogDetail(id);
|
||||
var service = GetRiskRuleService();
|
||||
var result = await Task.Run(() => service.GetAuditLogDetail(id));
|
||||
return Json(new { success = true, data = result });
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -674,12 +677,12 @@ namespace YLErp.Web.Controllers
|
||||
[HttpGet("risk-audit-logs/export")]
|
||||
[MyAuthorize("风险控制-风控日志导出")]
|
||||
/// <summary>导出风控操作日志为 Excel</summary>
|
||||
public IActionResult ExportRiskAuditLogs(QueryRiskAuditLogReq req)
|
||||
public async Task<IActionResult> ExportRiskAuditLogs(QueryRiskAuditLogReq req)
|
||||
{
|
||||
try
|
||||
{
|
||||
var service = new RiskRuleService(CurUser);
|
||||
var bytes = service.ExportAuditLogs(req);
|
||||
var service = GetRiskRuleService();
|
||||
var bytes = await Task.Run(() => service.ExportAuditLogs(req));
|
||||
return File(bytes, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "风控操作日志.xlsx");
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
@@ -695,4 +698,4 @@ namespace YLErp.Web.Controllers
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2513,7 +2513,7 @@ namespace YLErp.Web.Controllers
|
||||
{
|
||||
if (result.OldRiskNeedSpecialApproval)
|
||||
{
|
||||
return JsonSuccessData(new { proccessType = "AdditionalProcessing", source = "OldRiskQuotaTrialError", type = tradeBLL.LackOfMoney, TrialDataId = result.TrialDataId, message = result.errorMsg, typecode = result.type });
|
||||
return JsonSuccessData(new { proccessType = "AdditionalProcessing", source = "OldRiskQuotaTrialError", type = PS.Config.ErpElement.Company == Configuration.CompanyEnum.天风 || config.SpecialOperateForTrade == 1 ? tradeBLL.LackOfMoney : "", TrialDataId = result.TrialDataId, message = result.errorMsg, typecode = result.type });
|
||||
}
|
||||
return JsonSuccessData(new { proccessType = "QuotaTrialError", TrialDataId = result.TrialDataId, message = result.errorMsg, typecode = result.type });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user