修复平仓风控二次确认重复弹窗

This commit is contained in:
ruisu
2026-08-24 17:59:29 +08:00
parent 995cac356b
commit ad3bd10d65
3 changed files with 51 additions and 20 deletions
+23 -10
View File
@@ -45,11 +45,11 @@ namespace YLErp.Modules.RiskEngine
throw new ArgumentException("风控触发时点不能为空", nameof(context));
}
var confirmedRuleIds = new HashSet<string>();
var ignoreRiskRuleIds = new HashSet<string>();
var confirmationExpired = false;
if (confirmation != null)
{
confirmationExpired = !TryGetConfirmedRuleIds(context, trialSource, confirmation, confirmedRuleIds);
confirmationExpired = !TryLoadIgnoreRiskRuleIds(context, trialSource, confirmation, ignoreRiskRuleIds);
}
var riskResult = new RiskEngineService(this).EvaluateRisk(context, context.TriggerPoint);
@@ -63,10 +63,10 @@ namespace YLErp.Modules.RiskEngine
// 二次提交时,若首次试算记录有效,则剔除已确认过的审批和提示规则;记录过期或上下文不匹配时重新展示全部当前命中的审批和提示规则。
var pendingApprovalRules = confirmationExpired
? currentApprovalRules
: currentApprovalRules.Where(rule => !confirmedRuleIds.Contains(rule.RuleId)).ToList();
: currentApprovalRules.Where(rule => !ignoreRiskRuleIds.Contains(rule.RuleId)).ToList();
var pendingTipRules = confirmationExpired
? currentTipRules
: currentTipRules.Where(rule => !confirmedRuleIds.Contains(rule.RuleId)).ToList();
: currentTipRules.Where(rule => !ignoreRiskRuleIds.Contains(rule.RuleId)).ToList();
var trial = CreateQuotaTrial(context, trialSource, riskResult, pendingApprovalRules, pendingTipRules);
// 目前复用 quotaTrial 承载风控试算结果,兼容交易确认、平仓等现有详情页和二次确认流程;后续若表语义收敛,再考虑统一重命名为风控试算。
new Modules.RiskModule.QuotaMonitorService(this).SaveQuotaTrial(trial);
@@ -94,7 +94,7 @@ namespace YLErp.Modules.RiskEngine
/// <summary>
/// 校验二次确认记录,并恢复首次试算中已确认的审批和提示规则ID。
/// </summary>
private bool TryGetConfirmedRuleIds(RiskContext context, int trialSource, RiskTrialConfirmation confirmation, ISet<string> confirmedRuleIds)
private bool TryLoadIgnoreRiskRuleIds(RiskContext context, int trialSource, RiskTrialConfirmation confirmation, ISet<string> ignoreRiskRuleIds)
{
if (confirmation.TrialDataId <= 0 || confirmation.ExpireSeconds <= 0)
{
@@ -115,11 +115,11 @@ namespace YLErp.Modules.RiskEngine
return false;
}
foreach (var ruleId in ParseConfirmedRuleIds(trial.RiskWarningDetails))
foreach (var ruleId in GetIgnoreRiskRuleIds(confirmation, trial.RiskWarningDetails))
{
confirmedRuleIds.Add(ruleId);
ignoreRiskRuleIds.Add(ruleId);
}
return confirmedRuleIds.Count > 0;
return true;
}
/// <summary>
@@ -133,10 +133,18 @@ namespace YLErp.Modules.RiskEngine
.Any(line => string.Equals(line, expectedContext, StringComparison.Ordinal));
}
private static IEnumerable<string> GetIgnoreRiskRuleIds(RiskTrialConfirmation confirmation, string details)
{
var ignoreRiskRuleIds = confirmation.IgnoreRiskRuleIds ?? new List<string>();
return ignoreRiskRuleIds.Any()
? ignoreRiskRuleIds.Where(ruleId => !string.IsNullOrWhiteSpace(ruleId)).Select(ruleId => ruleId.Trim()).Distinct()
: ParseIgnoreRiskRuleIds(details);
}
/// <summary>
/// 从系统生成的审批和提示规则明细中恢复规则ID,避免直接信任前端提交的放行规则列表
/// 从系统生成的审批和提示规则明细中恢复规则ID,兼容未回传忽略规则ID的旧入口
/// </summary>
private static IEnumerable<string> ParseConfirmedRuleIds(string details)
private static IEnumerable<string> ParseIgnoreRiskRuleIds(string details)
{
const string ruleIdPrefix = "规则ID:";
var inConfirmableSection = false;
@@ -270,6 +278,11 @@ namespace YLErp.Modules.RiskEngine
/// 首次试算允许确认放行的有效时长,单位为秒。
/// </summary>
public int ExpireSeconds { get; set; }
/// <summary>
/// 首次试算返回并经前端回传的需忽略规则ID。
/// </summary>
public List<string> IgnoreRiskRuleIds { get; set; } = new List<string>();
}
/// <summary>
+22 -7
View File
@@ -304,10 +304,11 @@ namespace YLErp.Web.Controllers
/// </summary>
/// <param name="unwindData">本次单标的平仓数据。</param>
/// <param name="trialDataId">首次新风控试算记录ID;二次确认时传入。</param>
/// <param name="ignoreRiskRuleIds">首次试算返回的需忽略规则ID;二次确认时传入。</param>
/// <returns>平仓结果或新风控确认信息。</returns>
public JsonResult SwapUnwindJson(UnwindData unwindData, int? trialDataId = null)
public JsonResult SwapUnwindJson(UnwindData unwindData, int? trialDataId = null, string ignoreRiskRuleIds = null)
{
var result = new SwapDealService(CurUser).SwapUnwind(unwindData, CreateRiskTrialConfirmation(trialDataId));
var result = new SwapDealService(CurUser).SwapUnwind(unwindData, CreateRiskTrialConfirmation(trialDataId, ignoreRiskRuleIds));
return BuildCloseRiskResult(result, "平仓成功");
}
/// <summary>
@@ -346,10 +347,11 @@ namespace YLErp.Web.Controllers
/// <param name="unwindData">本次互换或平仓数据。</param>
/// <param name="eventType">事件类型。</param>
/// <param name="trialDataId">首次新风控试算记录ID;平仓二次确认时传入。</param>
/// <param name="ignoreRiskRuleIds">首次试算返回的需忽略规则ID;二次确认时传入。</param>
/// <returns>提交结果或新风控确认信息。</returns>
public JsonResult ApplyUnwind(UnwindData unwindData, int eventType, int? trialDataId = null)
public JsonResult ApplyUnwind(UnwindData unwindData, int eventType, int? trialDataId = null, string ignoreRiskRuleIds = null)
{
var result = new SwapDealService(CurUser).ApplySwapTrade(unwindData, eventType, CreateRiskTrialConfirmation(trialDataId));
var result = new SwapDealService(CurUser).ApplySwapTrade(unwindData, eventType, CreateRiskTrialConfirmation(trialDataId, ignoreRiskRuleIds));
return BuildCloseRiskResult(result, "提交成功");
}
@@ -379,8 +381,9 @@ namespace YLErp.Web.Controllers
/// 根据首次试算记录ID创建平仓新风控二次确认参数。
/// </summary>
/// <param name="trialDataId">首次新风控试算记录ID。</param>
/// <returns>首次提交返回空,二次确认返回包含有效期的确认参数。</returns>
private static RiskTrialConfirmation CreateRiskTrialConfirmation(int? trialDataId)
/// <param name="ignoreRiskRuleIds">首次试算返回的需忽略规则ID,多个ID使用逗号分隔。</param>
/// <returns>首次提交返回空,二次确认返回包含有效期和需忽略规则ID的确认参数。</returns>
private static RiskTrialConfirmation CreateRiskTrialConfirmation(int? trialDataId, string ignoreRiskRuleIds)
{
if (!trialDataId.HasValue)
{
@@ -398,10 +401,21 @@ namespace YLErp.Web.Controllers
return new RiskTrialConfirmation
{
TrialDataId = trialDataId.Value,
ExpireSeconds = expireSeconds
ExpireSeconds = expireSeconds,
IgnoreRiskRuleIds = ParseIgnoreRiskRuleIds(ignoreRiskRuleIds)
};
}
private static List<string> ParseIgnoreRiskRuleIds(string ignoreRiskRuleIds)
{
return (ignoreRiskRuleIds ?? string.Empty)
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(ruleId => ruleId.Trim())
.Where(ruleId => !string.IsNullOrWhiteSpace(ruleId))
.Distinct()
.ToList();
}
/// <summary>
/// 将平仓新风控结果转换为控制器统一JSON响应。
/// </summary>
@@ -432,6 +446,7 @@ namespace YLErp.Web.Controllers
source = "RiskWarning",
type = "RiskWarningConfirm",
result.TrialDataId,
ignoreRiskRuleIds = result.ApprovalRuleIds,
message = result.ConfirmationExpired ? $"原风控确认已超时,请重新确认。{result.Message}" : result.Message
});
}
@@ -371,11 +371,14 @@ const vue = new Vue({
postData.eventType = 2;//互换3,平仓2
}
// 提交平仓并处理新风控阻断、二次确认和成功提示。
var submitClose = function (trialDataId) {
var submitClose = function (trialDataId, ignoreRiskRuleIds) {
var requestData = _.cloneDeep(postData);
if (trialDataId) {
requestData.trialDataId = trialDataId;
}
if (ignoreRiskRuleIds && ignoreRiskRuleIds.length > 0) {
requestData.ignoreRiskRuleIds = ignoreRiskRuleIds.join(',');
}
main.post(postUrl, requestData).done(function (res) {
var riskData = res.obj;
if (riskData && riskData.proccessType === "QuotaTrialError") {
@@ -397,7 +400,7 @@ const vue = new Vue({
return;
}
if (res.success && riskData && riskData.proccessType === "AdditionalProcessing" && riskData.TrialDataId) {
// 审批类规则由用户填写说明并确认,二次提交回传后端生成的试算记录ID。
// 审批类规则由用户填写说明并确认,二次提交回传试算记录ID和需忽略规则ID。
var riskTrialLayerIndex = layer.open({
type: 2,
title: "风控试算详情",
@@ -418,7 +421,7 @@ const vue = new Vue({
remark: trialPage.Data.Remark
}).done(function () {
layer.close(riskTrialLayerIndex);
submitClose(riskData.TrialDataId);
submitClose(riskData.TrialDataId, riskData.ignoreRiskRuleIds || []);
});
}
});