524 lines
20 KiB
C#
524 lines
20 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Threading.Tasks;
|
||
using FreeSql;
|
||
using NPP.SmartSchedue.Api.Core.Repositories;
|
||
using NPP.SmartSchedue.Api.Contracts.Domain.Integration;
|
||
using NPP.SmartSchedue.Api.Contracts.Services.Integration.Output;
|
||
using ZhonTai.Admin.Core.Db.Transaction;
|
||
|
||
namespace NPP.SmartSchedue.Api.Repositories.Integration
|
||
{
|
||
/// <summary>
|
||
/// 智能整合记录仓储实现类
|
||
///
|
||
/// 业务实现思考:
|
||
/// 1. 充分利用FreeSql的强大功能,包括分页、索引优化、JSON查询等
|
||
/// 2. 考虑查询性能,合理使用索引和查询优化策略
|
||
/// 3. 实现完整的统计分析功能,为业务决策提供数据支持
|
||
/// 4. 处理大数据量场景,提供高效的分页和聚合查询
|
||
/// </summary>
|
||
public class IntegrationRecordRepository : AppRepositoryBase<IntegrationRecordEntity>, IIntegrationRecordRepository
|
||
{
|
||
public IntegrationRecordRepository(UnitOfWorkManagerCloud unitOfWorkManager) : base(unitOfWorkManager)
|
||
{
|
||
}
|
||
|
||
#region 基础查询方法
|
||
|
||
/// <summary>
|
||
/// 根据批次编码获取整合记录
|
||
/// 利用唯一索引,确保查询性能
|
||
/// </summary>
|
||
public async Task<IntegrationRecordEntity?> GetByBatchCodeAsync(string batchCode)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(batchCode))
|
||
return null;
|
||
|
||
return await Select
|
||
.Where(r => r.IntegrationBatchCode == batchCode)
|
||
.FirstAsync();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取指定时间范围内的整合记录
|
||
/// 使用时间索引优化查询性能
|
||
/// </summary>
|
||
public async Task<(List<IntegrationRecordEntity> Records, long Total)> GetByTimeRangeAsync(
|
||
DateTime startTime,
|
||
DateTime endTime,
|
||
int pageIndex = 1,
|
||
int pageSize = 20)
|
||
{
|
||
var query = Select
|
||
.Where(r => r.IntegrationTime >= startTime && r.IntegrationTime <= endTime)
|
||
.OrderByDescending(r => r.IntegrationTime);
|
||
|
||
var total = await query.CountAsync();
|
||
var records = await query
|
||
.Page(pageIndex, pageSize)
|
||
.ToListAsync();
|
||
|
||
return (records, total);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据操作人员获取整合记录
|
||
/// 使用操作员索引优化查询
|
||
/// </summary>
|
||
public async Task<(List<IntegrationRecordEntity> Records, long Total)> GetByOperatorAsync(
|
||
long operatorUserId,
|
||
int pageIndex = 1,
|
||
int pageSize = 20)
|
||
{
|
||
var query = Select
|
||
.Where(r => r.OperatorUserId == operatorUserId)
|
||
.OrderByDescending(r => r.IntegrationTime);
|
||
|
||
var total = await query.CountAsync();
|
||
var records = await query
|
||
.Page(pageIndex, pageSize)
|
||
.ToListAsync();
|
||
|
||
return (records, total);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据项目编号获取相关整合记录
|
||
/// 使用字符串包含查询,注意性能优化
|
||
/// </summary>
|
||
public async Task<(List<IntegrationRecordEntity> Records, long Total)> GetByProjectNumberAsync(
|
||
string projectNumber,
|
||
int pageIndex = 1,
|
||
int pageSize = 20)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(projectNumber))
|
||
return (new List<IntegrationRecordEntity>(), 0);
|
||
|
||
var query = Select
|
||
.Where(r => r.ProjectNumbers.Contains(projectNumber))
|
||
.OrderByDescending(r => r.IntegrationTime);
|
||
|
||
var total = await query.CountAsync();
|
||
var records = await query
|
||
.Page(pageIndex, pageSize)
|
||
.ToListAsync();
|
||
|
||
return (records, total);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 复合查询方法
|
||
|
||
/// <summary>
|
||
/// 多维度综合查询整合记录
|
||
/// 动态构建查询条件,支持灵活的业务查询需求
|
||
/// </summary>
|
||
public async Task<(List<IntegrationRecordEntity> Records, long Total)> GetByMultipleConditionsAsync(
|
||
long? operatorUserId = null,
|
||
string? projectNumber = null,
|
||
string? integrationType = null,
|
||
DateTime? startTime = null,
|
||
DateTime? endTime = null,
|
||
decimal? minSuccessRate = null,
|
||
int pageIndex = 1,
|
||
int pageSize = 20)
|
||
{
|
||
var query = Select;
|
||
|
||
// 动态添加查询条件
|
||
if (operatorUserId.HasValue)
|
||
{
|
||
query = query.Where(r => r.OperatorUserId == operatorUserId.Value);
|
||
}
|
||
|
||
if (!string.IsNullOrWhiteSpace(projectNumber))
|
||
{
|
||
query = query.Where(r => r.ProjectNumbers.Contains(projectNumber));
|
||
}
|
||
|
||
if (!string.IsNullOrWhiteSpace(integrationType))
|
||
{
|
||
query = query.Where(r => r.IntegrationType == integrationType);
|
||
}
|
||
|
||
if (startTime.HasValue)
|
||
{
|
||
query = query.Where(r => r.IntegrationTime >= startTime.Value);
|
||
}
|
||
|
||
if (endTime.HasValue)
|
||
{
|
||
query = query.Where(r => r.IntegrationTime <= endTime.Value);
|
||
}
|
||
|
||
if (minSuccessRate.HasValue)
|
||
{
|
||
// 使用计算字段进行筛选
|
||
query = query.Where(r => r.SuccessTaskCount + r.FailedTaskCount > 0)
|
||
.Where(r => (decimal)r.SuccessTaskCount / (r.SuccessTaskCount + r.FailedTaskCount) * 100 >= minSuccessRate.Value);
|
||
}
|
||
|
||
var orderedQuery = query.OrderByDescending(r => r.IntegrationTime);
|
||
|
||
var total = await orderedQuery.CountAsync();
|
||
var records = await orderedQuery
|
||
.Page(pageIndex, pageSize)
|
||
.ToListAsync();
|
||
|
||
return (records, total);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取包含指定任务的整合记录
|
||
/// 使用JSON查询功能,在TaskIdsJson中搜索任务ID
|
||
/// </summary>
|
||
public async Task<List<IntegrationRecordEntity>> GetRecordsContainingTaskAsync(long taskId)
|
||
{
|
||
// 使用FreeSql的JSON查询功能,支持JSON数组格式
|
||
return await Select
|
||
.Where(r => r.TaskIdsJson.Contains($"\"{taskId}\"") || r.TaskIdsJson.Contains($"{taskId}"))
|
||
.OrderByDescending(r => r.IntegrationTime)
|
||
.ToListAsync();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 统计分析方法
|
||
|
||
/// <summary>
|
||
/// 获取指定时间段的整合统计数据
|
||
/// 使用聚合查询生成统计报表
|
||
/// </summary>
|
||
public async Task<IntegrationStatistics> GetIntegrationStatisticsAsync(DateTime startTime, DateTime endTime)
|
||
{
|
||
var records = await Select
|
||
.Where(r => r.IntegrationTime >= startTime && r.IntegrationTime <= endTime)
|
||
.Where(r => !r.IsTestData) // 排除测试数据
|
||
.ToListAsync();
|
||
|
||
if (!records.Any())
|
||
{
|
||
return new IntegrationStatistics
|
||
{
|
||
StartTime = startTime,
|
||
EndTime = endTime
|
||
};
|
||
}
|
||
|
||
var totalTasks = records.Sum(r => r.SuccessTaskCount + r.FailedTaskCount);
|
||
var successfulTasks = records.Sum(r => r.SuccessTaskCount);
|
||
var failedTasks = records.Sum(r => r.FailedTaskCount);
|
||
|
||
return new IntegrationStatistics
|
||
{
|
||
StartTime = startTime,
|
||
EndTime = endTime,
|
||
TotalIntegrations = records.Count,
|
||
TotalTasks = totalTasks,
|
||
SuccessfulTasks = successfulTasks,
|
||
FailedTasks = failedTasks,
|
||
AverageSuccessRate = totalTasks > 0 ? Math.Round((decimal)successfulTasks / totalTasks * 100, 2) : 0,
|
||
AverageElapsedTime = records.Any() ? (long)records.Average(r => r.ElapsedMilliseconds) : 0,
|
||
AveragePersonnelFairnessScore = records.Any() ? Math.Round((decimal)records.Average(r => r.PersonnelFairnessScore), 1) : 0,
|
||
AverageEquipmentUtilizationRate = records.Any() ? Math.Round(records.Average(r => r.EquipmentUtilizationRate), 1) : 0,
|
||
ActiveOperatorCount = records.Select(r => r.OperatorUserId).Distinct().Count(),
|
||
InvolvedProjectCount = records
|
||
.Where(r => !string.IsNullOrWhiteSpace(r.ProjectNumbers))
|
||
.SelectMany(r => r.GetProjectNumbers())
|
||
.Distinct()
|
||
.Count()
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取操作员整合统计数据
|
||
/// 针对特定操作员的详细统计分析
|
||
/// </summary>
|
||
public async Task<OperatorIntegrationStats> GetOperatorStatisticsAsync(
|
||
long operatorUserId,
|
||
DateTime startTime,
|
||
DateTime endTime)
|
||
{
|
||
var records = await Select
|
||
.Where(r => r.OperatorUserId == operatorUserId)
|
||
.Where(r => r.IntegrationTime >= startTime && r.IntegrationTime <= endTime)
|
||
.Where(r => !r.IsTestData)
|
||
.OrderByDescending(r => r.IntegrationTime)
|
||
.ToListAsync();
|
||
|
||
if (!records.Any())
|
||
{
|
||
var operatorInfo = await Select
|
||
.Where(r => r.OperatorUserId == operatorUserId)
|
||
.OrderByDescending(r => r.IntegrationTime)
|
||
.FirstAsync();
|
||
|
||
return new OperatorIntegrationStats
|
||
{
|
||
OperatorUserId = operatorUserId,
|
||
OperatorUserName = operatorInfo?.OperatorUserName ?? "",
|
||
OperatorRealName = operatorInfo?.OperatorRealName ?? ""
|
||
};
|
||
}
|
||
|
||
var totalTasks = records.Sum(r => r.SuccessTaskCount + r.FailedTaskCount);
|
||
var successfulTasks = records.Sum(r => r.SuccessTaskCount);
|
||
|
||
return new OperatorIntegrationStats
|
||
{
|
||
OperatorUserId = operatorUserId,
|
||
OperatorUserName = records.First().OperatorUserName,
|
||
OperatorRealName = records.First().OperatorRealName,
|
||
IntegrationCount = records.Count,
|
||
TotalTasks = totalTasks,
|
||
AverageSuccessRate = totalTasks > 0 ? Math.Round((decimal)successfulTasks / totalTasks * 100, 2) : 0,
|
||
TotalElapsedTime = records.Sum(r => r.ElapsedMilliseconds),
|
||
AverageIntegrationTime = records.Any() ? (long)records.Average(r => r.ElapsedMilliseconds) : 0,
|
||
LastOperationTime = records.Max(r => r.IntegrationTime)
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取策略效果分析数据
|
||
/// 分析不同分配策略的效果,支持策略优化决策
|
||
/// </summary>
|
||
public async Task<List<StrategyEffectivenessStats>> GetStrategyEffectivenessAsync(
|
||
DateTime startTime,
|
||
DateTime endTime)
|
||
{
|
||
var records = await Select
|
||
.Where(r => r.IntegrationTime >= startTime && r.IntegrationTime <= endTime)
|
||
.Where(r => !r.IsTestData)
|
||
.ToListAsync();
|
||
|
||
if (!records.Any())
|
||
return new List<StrategyEffectivenessStats>();
|
||
|
||
// 解析策略配置并进行分组统计
|
||
var strategyGroups = records
|
||
.Where(r => !string.IsNullOrWhiteSpace(r.StrategyConfigJson))
|
||
.GroupBy(r => r.StrategyConfigJson) // 按策略配置JSON分组
|
||
.Select(g => new StrategyEffectivenessStats
|
||
{
|
||
PersonnelStrategy = ExtractPersonnelStrategyFromJson(g.Key),
|
||
EquipmentStrategy = ExtractEquipmentStrategyFromJson(g.Key),
|
||
UsageCount = g.Count(),
|
||
AverageSuccessRate = CalculateGroupSuccessRate(g.ToList()),
|
||
AveragePersonnelFairnessScore = Math.Round((decimal)g.Average(r => r.PersonnelFairnessScore), 1),
|
||
AverageEquipmentUtilizationRate = Math.Round(g.Average(r => r.EquipmentUtilizationRate), 1),
|
||
AverageElapsedTime = (long)g.Average(r => r.ElapsedMilliseconds)
|
||
})
|
||
.OrderByDescending(s => s.UsageCount)
|
||
.ToList();
|
||
|
||
return strategyGroups;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取整合性能趋势数据
|
||
/// 生成性能趋势图表数据,支持性能监控
|
||
/// </summary>
|
||
public async Task<List<IntegrationPerformanceTrend>> GetPerformanceTrendAsync(int days = 30)
|
||
{
|
||
var startDate = DateTime.Today.AddDays(-days + 1);
|
||
var endDate = DateTime.Today.AddDays(1);
|
||
|
||
var records = await Select
|
||
.Where(r => r.IntegrationTime >= startDate && r.IntegrationTime < endDate)
|
||
.Where(r => !r.IsTestData)
|
||
.ToListAsync();
|
||
|
||
var trends = records
|
||
.GroupBy(r => r.IntegrationTime.Date)
|
||
.Select(g => new IntegrationPerformanceTrend
|
||
{
|
||
Date = g.Key,
|
||
IntegrationCount = g.Count(),
|
||
AverageSuccessRate = CalculateGroupSuccessRate(g.ToList()),
|
||
AverageElapsedTime = (long)g.Average(r => r.ElapsedMilliseconds),
|
||
TotalTasks = g.Sum(r => r.SuccessTaskCount + r.FailedTaskCount)
|
||
})
|
||
.OrderBy(t => t.Date)
|
||
.ToList();
|
||
|
||
// 填充没有数据的日期
|
||
var allDates = Enumerable.Range(0, days)
|
||
.Select(i => startDate.AddDays(i))
|
||
.ToList();
|
||
|
||
var completeTrends = allDates
|
||
.Select(date => trends.FirstOrDefault(t => t.Date == date) ?? new IntegrationPerformanceTrend
|
||
{
|
||
Date = date,
|
||
IntegrationCount = 0,
|
||
AverageSuccessRate = 0,
|
||
AverageElapsedTime = 0,
|
||
TotalTasks = 0
|
||
})
|
||
.ToList();
|
||
|
||
return completeTrends;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 业务专用方法
|
||
|
||
/// <summary>
|
||
/// 检查批次编码是否已存在
|
||
/// 利用唯一索引快速查询
|
||
/// </summary>
|
||
public async Task<bool> BatchCodeExistsAsync(string batchCode)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(batchCode))
|
||
return false;
|
||
|
||
return await Select
|
||
.Where(r => r.IntegrationBatchCode == batchCode)
|
||
.AnyAsync();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取最近的整合记录
|
||
/// 支持监控面板和快速状态查看
|
||
/// </summary>
|
||
public async Task<List<IntegrationRecordEntity>> GetRecentRecordsAsync(int count = 10)
|
||
{
|
||
return await Select
|
||
.Where(r => !r.IsTestData)
|
||
.OrderByDescending(r => r.IntegrationTime)
|
||
.Take(count)
|
||
.ToListAsync();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取失败率高的整合记录
|
||
/// 支持质量监控和问题识别
|
||
/// </summary>
|
||
public async Task<List<IntegrationRecordEntity>> GetHighFailureRateRecordsAsync(
|
||
decimal minFailureRate,
|
||
DateTime startTime,
|
||
DateTime endTime,
|
||
int count = 50)
|
||
{
|
||
return await Select
|
||
.Where(r => r.IntegrationTime >= startTime && r.IntegrationTime <= endTime)
|
||
.Where(r => !r.IsTestData)
|
||
.Where(r => r.SuccessTaskCount + r.FailedTaskCount > 0) // 确保有任务数据
|
||
.ToListAsync()
|
||
.ContinueWith(task =>
|
||
{
|
||
var records = task.Result;
|
||
return records
|
||
.Where(r =>
|
||
{
|
||
var totalTasks = r.SuccessTaskCount + r.FailedTaskCount;
|
||
var failureRate = totalTasks > 0 ? (decimal)r.FailedTaskCount / totalTasks * 100 : 0;
|
||
return failureRate >= minFailureRate;
|
||
})
|
||
.OrderByDescending(r => (decimal)r.FailedTaskCount / (r.SuccessTaskCount + r.FailedTaskCount))
|
||
.Take(count)
|
||
.ToList();
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 软删除过期的测试数据
|
||
/// 定期数据清理,保持系统性能
|
||
/// </summary>
|
||
public async Task<int> SoftDeleteExpiredTestDataAsync(DateTime beforeDate)
|
||
{
|
||
var expiredRecords = await Select
|
||
.Where(r => r.IsTestData && r.CreatedTime < beforeDate)
|
||
.Where(r => !r.IsDeleted)
|
||
.ToListAsync();
|
||
|
||
if (!expiredRecords.Any())
|
||
return 0;
|
||
|
||
// 批量软删除
|
||
var deletedCount = await UpdateDiy
|
||
.Set(r => r.IsDeleted, true)
|
||
.Set(r => r.ModifiedTime, DateTime.Now)
|
||
.Where(r => expiredRecords.Select(er => er.Id).Contains(r.Id))
|
||
.ExecuteAffrowsAsync();
|
||
|
||
return deletedCount;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 私有辅助方法
|
||
|
||
/// <summary>
|
||
/// 从策略JSON中提取人员策略
|
||
/// </summary>
|
||
private string ExtractPersonnelStrategyFromJson(string strategyConfigJson)
|
||
{
|
||
try
|
||
{
|
||
if (string.IsNullOrWhiteSpace(strategyConfigJson))
|
||
return "未知";
|
||
|
||
using var document = System.Text.Json.JsonDocument.Parse(strategyConfigJson);
|
||
var root = document.RootElement;
|
||
|
||
if (root.TryGetProperty("PersonnelStrategy", out var personnelStrategyProp))
|
||
{
|
||
return personnelStrategyProp.GetString() ?? "未知";
|
||
}
|
||
|
||
return "未知";
|
||
}
|
||
catch
|
||
{
|
||
return "未知";
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从策略JSON中提取设备策略
|
||
/// </summary>
|
||
private string ExtractEquipmentStrategyFromJson(string strategyConfigJson)
|
||
{
|
||
try
|
||
{
|
||
if (string.IsNullOrWhiteSpace(strategyConfigJson))
|
||
return "未知";
|
||
|
||
using var document = System.Text.Json.JsonDocument.Parse(strategyConfigJson);
|
||
var root = document.RootElement;
|
||
|
||
if (root.TryGetProperty("EquipmentStrategy", out var equipmentStrategyProp))
|
||
{
|
||
return equipmentStrategyProp.GetString() ?? "未知";
|
||
}
|
||
|
||
return "未知";
|
||
}
|
||
catch
|
||
{
|
||
return "未知";
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算分组的平均成功率
|
||
/// </summary>
|
||
private decimal CalculateGroupSuccessRate(List<IntegrationRecordEntity> records)
|
||
{
|
||
if (!records.Any())
|
||
return 0;
|
||
|
||
var totalTasks = records.Sum(r => r.SuccessTaskCount + r.FailedTaskCount);
|
||
var successfulTasks = records.Sum(r => r.SuccessTaskCount);
|
||
|
||
return totalTasks > 0 ? Math.Round((decimal)successfulTasks / totalTasks * 100, 2) : 0;
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
} |