|
|
@@ -31,29 +31,37 @@ public class S8ExceptionService : ITransient
|
|
|
(q.Page, q.PageSize) = PagingGuard.Normalize(q.Page, q.PageSize);
|
|
|
var pendingStatuses = new[] { "NEW", "ASSIGNED", "IN_PROGRESS", "PENDING_VERIFICATION" };
|
|
|
|
|
|
+ var includeUnclassified = q.IncludeUnclassified == true;
|
|
|
+
|
|
|
var query = _rep.Context.Queryable<AdoS8Exception>()
|
|
|
.LeftJoin<AdoS8SceneConfig>((e, sc) =>
|
|
|
e.TenantId == sc.TenantId && e.FactoryId == sc.FactoryId && e.SceneCode == sc.SceneCode)
|
|
|
- .Where((e, sc) => e.TenantId == q.TenantId && e.FactoryId == q.FactoryId && !e.IsDeleted)
|
|
|
- .WhereIF(!string.IsNullOrWhiteSpace(q.Status), (e, sc) => e.Status == q.Status)
|
|
|
+ .LeftJoin<AdoS8WatchRule>((e, sc, wr) =>
|
|
|
+ e.TenantId == wr.TenantId && e.FactoryId == wr.FactoryId && e.SourceRuleCode == wr.RuleCode)
|
|
|
+ .Where((e, sc, wr) => e.TenantId == q.TenantId && e.FactoryId == q.FactoryId && !e.IsDeleted)
|
|
|
+ .WhereIF(!includeUnclassified, (e, sc, wr) => !SqlFunc.IsNullOrEmpty(e.ExceptionTypeCode))
|
|
|
+ .WhereIF(!string.IsNullOrWhiteSpace(q.Status), (e, sc, wr) => e.Status == q.Status)
|
|
|
.WhereIF(string.IsNullOrWhiteSpace(q.Status) && q.StatusBucket == "pending",
|
|
|
- (e, sc) => pendingStatuses.Contains(e.Status))
|
|
|
- .WhereIF(!string.IsNullOrWhiteSpace(q.Severity), (e, sc) => e.Severity == q.Severity)
|
|
|
- .WhereIF(!string.IsNullOrWhiteSpace(q.SceneCode), (e, sc) => e.SceneCode == q.SceneCode)
|
|
|
- .WhereIF(!string.IsNullOrWhiteSpace(q.ModuleCode), (e, sc) => e.ModuleCode == q.ModuleCode)
|
|
|
- .WhereIF(q.DeptId.HasValue, (e, sc) => e.ResponsibleDeptId == q.DeptId!.Value || e.OccurrenceDeptId == q.DeptId!.Value)
|
|
|
- .WhereIF(q.TimeoutFlag.HasValue, (e, sc) => e.TimeoutFlag == q.TimeoutFlag!.Value)
|
|
|
- .WhereIF(q.BeginTime.HasValue, (e, sc) => e.CreatedAt >= q.BeginTime!.Value)
|
|
|
- .WhereIF(q.EndTime.HasValue, (e, sc) => e.CreatedAt <= q.EndTime!.Value)
|
|
|
- .WhereIF(!string.IsNullOrWhiteSpace(q.ProcessNodeCode), (e, sc) => e.ProcessNodeCode == q.ProcessNodeCode)
|
|
|
- .WhereIF(!string.IsNullOrWhiteSpace(q.RelatedObjectCode), (e, sc) => e.RelatedObjectCode == q.RelatedObjectCode)
|
|
|
+ (e, sc, wr) => pendingStatuses.Contains(e.Status))
|
|
|
+ .WhereIF(!string.IsNullOrWhiteSpace(q.Severity), (e, sc, wr) => e.Severity == q.Severity)
|
|
|
+ .WhereIF(!string.IsNullOrWhiteSpace(q.SceneCode), (e, sc, wr) => e.SceneCode == q.SceneCode)
|
|
|
+ .WhereIF(!string.IsNullOrWhiteSpace(q.ModuleCode), (e, sc, wr) => e.ModuleCode == q.ModuleCode)
|
|
|
+ .WhereIF(q.DeptId.HasValue, (e, sc, wr) => e.ResponsibleDeptId == q.DeptId!.Value || e.OccurrenceDeptId == q.DeptId!.Value)
|
|
|
+ .WhereIF(q.TimeoutFlag.HasValue, (e, sc, wr) => e.TimeoutFlag == q.TimeoutFlag!.Value)
|
|
|
+ .WhereIF(q.BeginTime.HasValue, (e, sc, wr) => e.CreatedAt >= q.BeginTime!.Value)
|
|
|
+ .WhereIF(q.EndTime.HasValue, (e, sc, wr) => e.CreatedAt <= q.EndTime!.Value)
|
|
|
+ .WhereIF(!string.IsNullOrWhiteSpace(q.ProcessNodeCode), (e, sc, wr) => e.ProcessNodeCode == q.ProcessNodeCode)
|
|
|
+ .WhereIF(!string.IsNullOrWhiteSpace(q.RelatedObjectCode), (e, sc, wr) => e.RelatedObjectCode == q.RelatedObjectCode)
|
|
|
+ .WhereIF(q.RecoveredStatus == "RECOVERED", (e, sc, wr) => e.RecoveredAt != null)
|
|
|
+ .WhereIF(q.RecoveredStatus == "ACTIVE", (e, sc, wr) => e.RecoveredAt == null)
|
|
|
+ .WhereIF(!string.IsNullOrWhiteSpace(q.RuleType), (e, sc, wr) => wr.RuleType == q.RuleType)
|
|
|
.WhereIF(!string.IsNullOrWhiteSpace(q.Keyword),
|
|
|
- (e, sc) => e.Title.Contains(q.Keyword!) || e.ExceptionCode.Contains(q.Keyword!));
|
|
|
+ (e, sc, wr) => e.Title.Contains(q.Keyword!) || e.ExceptionCode.Contains(q.Keyword!));
|
|
|
|
|
|
var total = await query.CountAsync();
|
|
|
var list = await query
|
|
|
- .OrderBy((e, sc) => e.CreatedAt, OrderByType.Desc)
|
|
|
- .Select((e, sc) => new AdoS8ExceptionListItemDto
|
|
|
+ .OrderBy((e, sc, wr) => e.CreatedAt, OrderByType.Desc)
|
|
|
+ .Select((e, sc, wr) => new AdoS8ExceptionListItemDto
|
|
|
{
|
|
|
Id = e.Id,
|
|
|
FactoryId = e.FactoryId,
|
|
|
@@ -70,7 +78,15 @@ public class S8ExceptionService : ITransient
|
|
|
SlaDeadline = e.SlaDeadline,
|
|
|
TimeoutFlag = e.TimeoutFlag,
|
|
|
CreatedAt = e.CreatedAt,
|
|
|
- ClosedAt = e.ClosedAt
|
|
|
+ ClosedAt = e.ClosedAt,
|
|
|
+ ExceptionTypeCode = e.ExceptionTypeCode,
|
|
|
+ RecoveredAt = e.RecoveredAt,
|
|
|
+ SourceRuleCode = e.SourceRuleCode,
|
|
|
+ SourceObjectType = e.SourceObjectType,
|
|
|
+ SourceObjectId = e.SourceObjectId,
|
|
|
+ DedupKey = e.DedupKey,
|
|
|
+ LastDetectedAt = e.LastDetectedAt,
|
|
|
+ RuleType = wr.RuleType
|
|
|
})
|
|
|
.ToPageListAsync(q.Page, q.PageSize);
|
|
|
|
|
|
@@ -112,8 +128,10 @@ public class S8ExceptionService : ITransient
|
|
|
var rows = await _rep.Context.Queryable<AdoS8Exception>()
|
|
|
.LeftJoin<AdoS8SceneConfig>((e, sc) =>
|
|
|
e.TenantId == sc.TenantId && e.FactoryId == sc.FactoryId && e.SceneCode == sc.SceneCode)
|
|
|
- .Where((e, sc) => e.Id == id && e.TenantId == tenantId && e.FactoryId == factoryId && !e.IsDeleted)
|
|
|
- .Select((e, sc) => new AdoS8ExceptionDetailDto
|
|
|
+ .LeftJoin<AdoS8WatchRule>((e, sc, wr) =>
|
|
|
+ e.TenantId == wr.TenantId && e.FactoryId == wr.FactoryId && e.SourceRuleCode == wr.RuleCode)
|
|
|
+ .Where((e, sc, wr) => e.Id == id && e.TenantId == tenantId && e.FactoryId == factoryId && !e.IsDeleted)
|
|
|
+ .Select((e, sc, wr) => new AdoS8ExceptionDetailDto
|
|
|
{
|
|
|
Id = e.Id,
|
|
|
FactoryId = e.FactoryId,
|
|
|
@@ -153,6 +171,8 @@ public class S8ExceptionService : ITransient
|
|
|
SourceRuleCode = e.SourceRuleCode,
|
|
|
SourceObjectType = e.SourceObjectType,
|
|
|
SourceObjectId = e.SourceObjectId,
|
|
|
+ ExceptionTypeCode = e.ExceptionTypeCode,
|
|
|
+ RuleType = wr.RuleType,
|
|
|
})
|
|
|
.Take(1)
|
|
|
.ToListAsync();
|
|
|
@@ -193,9 +213,13 @@ public class S8ExceptionService : ITransient
|
|
|
.ToListAsync())
|
|
|
.ToDictionary(x => x.Id, x => x.Name);
|
|
|
|
|
|
+ // EmployeeMaster.tenant_id 与 SysUser.TenantId 历史错位(797403760988229 ≠ 系统租户),
|
|
|
+ // 走全局 multi-tenant filter 会全过滤为空 → 详情页处理人/检验人姓名显示数字 ID。
|
|
|
+ // 与 S8MasterDataAdapter.GetEmployeesAsync / S8TaskFlowService.GetEmployeeSysUserIdAsync 同口径,
|
|
|
+ // 局部 ClearFilter + employee.Id 主键集合作为安全边界,无跨租户泄漏。
|
|
|
var empMap = empIds.Count == 0
|
|
|
? new Dictionary<long, string>()
|
|
|
- : (await _empRep.AsQueryable()
|
|
|
+ : (await _empRep.AsQueryable().ClearFilter()
|
|
|
.Where(x => empIds.Contains(x.Id))
|
|
|
.Select(x => new { x.Id, Name = x.Name ?? x.Employee })
|
|
|
.ToListAsync())
|