|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Threading.Tasks;
|
|
|
using Haoliang.Models.DataCollection;
|
|
|
using Haoliang.Models.Device;
|
|
|
using Haoliang.Models.System;
|
|
|
using Haoliang.Models.User;
|
|
|
using Haoliang.Models.Template;
|
|
|
using Haoliang.Models.Production;
|
|
|
using Haoliang.Data.Repositories;
|
|
|
|
|
|
namespace Haoliang.Core.Services
|
|
|
{
|
|
|
// 完整的仓储接口定义(确保所有服务都能编译)
|
|
|
public interface IAlarmRepository : IRepository<Alarm>
|
|
|
{
|
|
|
Task<IEnumerable<Alarm>> GetByDeviceIdAsync(int deviceId);
|
|
|
Task<IEnumerable<Alarm>> GetByAlarmTypeAsync(AlarmType type);
|
|
|
Task<IEnumerable<Alarm>> GetByStatusAsync(AlarmStatus status);
|
|
|
Task<IEnumerable<Alarm>> GetByDateRangeAsync(DateTime startDate, DateTime endDate);
|
|
|
Task<AlarmStatistics> GetAlarmStatisticsAsync(DateTime date);
|
|
|
Task<IEnumerable<Alarm>> GetBySeverityAsync(AlarmSeverity severity);
|
|
|
Task<IEnumerable<Alarm>> GetByDeviceAndDateRangeAsync(int deviceId, DateTime startDate, DateTime endDate);
|
|
|
}
|
|
|
|
|
|
public interface ISystemConfigRepository : IRepository<SystemConfig>
|
|
|
{
|
|
|
Task<SystemConfig> GetByKeyAsync(string configKey);
|
|
|
Task<bool> DeleteByKeyAsync(string configKey);
|
|
|
Task<bool> KeyExistsAsync(string configKey);
|
|
|
Task<IEnumerable<SystemConfig>> GetByCategoryAsync(string category);
|
|
|
SystemConfig UpsertAsync(SystemConfig config);
|
|
|
}
|
|
|
|
|
|
public interface ILogRepository : IRepository<LogEntry>
|
|
|
{
|
|
|
Task<IEnumerable<LogEntry>> GetLogsAsync(LogLevel? logLevel = null, DateTime? startDate = null, DateTime? endDate = null, string category = null);
|
|
|
Task<int> GetLogCountAsync(LogLevel? logLevel = null, DateTime? startDate = null, DateTime? endDate = null);
|
|
|
Task ArchiveLogsAsync(DateTime cutoffDate);
|
|
|
Task ClearLogsAsync();
|
|
|
}
|
|
|
|
|
|
public interface IScheduledTaskRepository : IRepository<ScheduledTask>
|
|
|
{
|
|
|
Task<IEnumerable<ScheduledTask>> GetActiveTasksAsync();
|
|
|
Task<IEnumerable<ScheduledTask>> GetTasksByStatusAsync(TaskStatus status);
|
|
|
Task<TaskExecutionResult> GetLastExecutionResultAsync(string taskId);
|
|
|
}
|
|
|
|
|
|
public interface IProgramProductionSummaryRepository : IRepository<ProgramProductionSummary>
|
|
|
{
|
|
|
Task<ProgramProductionSummary> GetByDeviceAndDateAsync(int deviceId, DateTime date);
|
|
|
Task<IEnumerable<ProgramProductionSummary>> GetByDateAsync(DateTime date);
|
|
|
Task<IEnumerable<ProgramProductionSummary>> GetByDeviceAsync(int deviceId);
|
|
|
}
|
|
|
|
|
|
public interface IUserRepository : IRepository<User>
|
|
|
{
|
|
|
Task<User> GetByUsernameAsync(string username);
|
|
|
Task<User> GetByEmailAsync(string email);
|
|
|
Task<bool> IsUsernameExistsAsync(string username);
|
|
|
Task<bool> IsEmailExistsAsync(string email);
|
|
|
Task<IEnumerable<User>> GetByRoleAsync(string roleName);
|
|
|
Task<IEnumerable<User>> GetByDepartmentAsync(string department);
|
|
|
}
|
|
|
|
|
|
// 增强的仓储接口
|
|
|
public interface IDeviceRepository : IRepository<CNCDevice>
|
|
|
{
|
|
|
Task<IEnumerable<CNCDevice>> GetOnlineDevicesAsync();
|
|
|
Task<IEnumerable<CNCDevice>> GetOfflineDevicesAsync();
|
|
|
Task<CNCDevice> GetByDeviceCodeAsync(string deviceCode);
|
|
|
Task<bool> IsDeviceOnlineAsync(int deviceId);
|
|
|
Task<IEnumerable<CNCDevice>> GetByTemplateAsync(int templateId);
|
|
|
Task UpdateDeviceStatusAsync(int deviceId, DeviceStatus status);
|
|
|
Task<DeviceStatistics> GetDeviceStatisticsAsync(int deviceId);
|
|
|
}
|
|
|
|
|
|
public interface ITemplateRepository : IRepository<CNCBrandTemplate>
|
|
|
{
|
|
|
Task<IEnumerable<CNCBrandTemplate>> GetByBrandAsync(string brandName);
|
|
|
Task<IEnumerable<CNCBrandTemplate>> GetActiveTemplatesAsync();
|
|
|
Task<bool> IsTemplateInUseAsync(int templateId);
|
|
|
Task<CNCBrandTemplate> GetByNameAsync(string templateName);
|
|
|
}
|
|
|
|
|
|
public interface IProductionRepository : IRepository<ProductionRecord>
|
|
|
{
|
|
|
Task<ProductionRecord> GetByDeviceAndDateAsync(int deviceId, DateTime date);
|
|
|
Task<IEnumerable<ProductionRecord>> GetByDateRangeAsync(int deviceId, DateTime startDate, DateTime endDate);
|
|
|
Task<ProductionStatistics> GetStatisticsAsync(int deviceId, DateTime date);
|
|
|
Task<ProductionSummary> GetSummaryAsync(DateTime date);
|
|
|
Task<bool> HasProductionDataAsync(int deviceId, DateTime date);
|
|
|
Task ArchiveProductionDataAsync(int daysToKeep = 90);
|
|
|
}
|
|
|
|
|
|
public interface ICollectionTaskRepository : IRepository<CollectionTask>
|
|
|
{
|
|
|
Task<IEnumerable<CollectionTask>> GetPendingTasksAsync();
|
|
|
Task<IEnumerable<CollectionTask>> GetFailedTasksAsync();
|
|
|
Task<CollectionTask> GetByDeviceAsync(int deviceId);
|
|
|
Task<bool> MarkTaskCompletedAsync(int taskId, bool isSuccess, string result);
|
|
|
}
|
|
|
|
|
|
public interface ICollectionResultRepository : IRepository<CollectionResult>
|
|
|
{
|
|
|
Task<IEnumerable<CollectionResult>> GetByDeviceAsync(int deviceId);
|
|
|
Task<IEnumerable<CollectionResult>> GetByDateRangeAsync(int deviceId, DateTime startDate, DateTime endDate);
|
|
|
Task<CollectionStatistics> GetStatisticsAsync(DateTime date);
|
|
|
Task<CollectionHealth> GetHealthAsync();
|
|
|
Task ArchiveResultsAsync(int daysToKeep = 30);
|
|
|
}
|
|
|
|
|
|
public interface ICollectionLogRepository : IRepository<CollectionLog>
|
|
|
{
|
|
|
Task<IEnumerable<CollectionLog>> GetByDeviceAsync(int deviceId);
|
|
|
Task<IEnumerable<CollectionLog>> GetByLogLevelAsync(LogLevel logLevel);
|
|
|
Task<int> GetErrorCountAsync(int deviceId);
|
|
|
Task ArchiveLogsAsync(int daysToKeep = 30);
|
|
|
Task ClearLogsAsync();
|
|
|
}
|
|
|
|
|
|
public interface IProductionSummaryRepository : IRepository<ProductionSummary>
|
|
|
{
|
|
|
Task<ProductionSummary> GetByDateAsync(DateTime date);
|
|
|
Task<IEnumerable<ProductionSummary>> GetByDateRangeAsync(DateTime startDate, DateTime endDate);
|
|
|
Task<ProductionSummary> GetByDeviceAndDateAsync(int deviceId, DateTime date);
|
|
|
Task<ProductionSummary> GetTodaySummaryAsync();
|
|
|
}
|
|
|
|
|
|
// 背景任务管理器
|
|
|
public class BackgroundTaskManager : ISchedulerService
|
|
|
{
|
|
|
private readonly IScheduledTaskRepository _taskRepository;
|
|
|
private readonly IProductionService _productionService;
|
|
|
private readonly ILoggingService _loggingService;
|
|
|
private readonly ConcurrentDictionary<string, Task> _runningTasks = new();
|
|
|
private readonly ConcurrentDictionary<string, bool> _taskStatus = new();
|
|
|
private System.Threading.Timer _schedulerTimer;
|
|
|
|
|
|
public BackgroundTaskManager(
|
|
|
IScheduledTaskRepository taskRepository,
|
|
|
IProductionService productionService,
|
|
|
ILoggingService loggingService)
|
|
|
{
|
|
|
_taskRepository = taskRepository;
|
|
|
_productionService = productionService;
|
|
|
_loggingService = loggingService;
|
|
|
}
|
|
|
|
|
|
public async Task StartSchedulerAsync()
|
|
|
{
|
|
|
_schedulerTimer = new System.Threading.Timer(
|
|
|
async _ => await CheckAndExecuteTasksAsync(),
|
|
|
null,
|
|
|
TimeSpan.Zero,
|
|
|
TimeSpan.FromMinutes(1));
|
|
|
|
|
|
await _loggingService.LogInfoAsync("Background task scheduler started");
|
|
|
}
|
|
|
|
|
|
public async Task StopSchedulerAsync()
|
|
|
{
|
|
|
_schedulerTimer?.Dispose();
|
|
|
_schedulerTimer = null;
|
|
|
|
|
|
foreach (var task in _runningTasks.Values)
|
|
|
{
|
|
|
if (!task.IsCompleted)
|
|
|
{
|
|
|
await Task.WhenAny(task, Task.Delay(TimeSpan.FromSeconds(5)));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
await _loggingService.LogInfoAsync("Background task scheduler stopped");
|
|
|
}
|
|
|
|
|
|
public async Task ScheduleTaskAsync(ScheduledTask task)
|
|
|
{
|
|
|
task.TaskStatus = TaskStatus.Pending;
|
|
|
task.CreatedAt = DateTime.Now;
|
|
|
task.LastRunAt = null;
|
|
|
|
|
|
await _taskRepository.AddAsync(task);
|
|
|
await _loggingService.LogInfoAsync($"Task {task.TaskName} scheduled");
|
|
|
}
|
|
|
|
|
|
public async Task<bool> RemoveTaskAsync(string taskId)
|
|
|
{
|
|
|
var task = await _taskRepository.GetByIdAsync(taskId);
|
|
|
if (task == null)
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// 如果任务正在运行,等待完成
|
|
|
if (_runningTasks.ContainsKey(taskId))
|
|
|
{
|
|
|
var runningTask = _runningTasks[taskId];
|
|
|
await Task.WhenAny(runningTask, Task.Delay(TimeSpan.FromSeconds(5)));
|
|
|
}
|
|
|
|
|
|
return await _taskRepository.DeleteAsync(taskId);
|
|
|
}
|
|
|
|
|
|
public async Task<IEnumerable<ScheduledTask>> GetAllScheduledTasksAsync()
|
|
|
{
|
|
|
return await _taskRepository.GetAllAsync();
|
|
|
}
|
|
|
|
|
|
public async Task<ScheduledTask> GetTaskByIdAsync(string taskId)
|
|
|
{
|
|
|
return await _taskRepository.GetByIdAsync(taskId);
|
|
|
}
|
|
|
|
|
|
public async Task ExecuteTaskAsync(string taskId)
|
|
|
{
|
|
|
if (_runningTasks.ContainsKey(taskId))
|
|
|
{
|
|
|
await _loggingService.LogWarningAsync($"Task {taskId} is already running");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
var task = await _taskRepository.GetByIdAsync(taskId);
|
|
|
if (task == null)
|
|
|
{
|
|
|
await _loggingService.LogErrorAsync($"Task {taskId} not found");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
var taskExecution = Task.Run(async () =>
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
_taskStatus[taskId] = true;
|
|
|
task.TaskStatus = TaskStatus.Running;
|
|
|
task.LastRunAt = DateTime.Now;
|
|
|
await _taskRepository.UpdateAsync(task);
|
|
|
|
|
|
await _loggingService.LogInfoAsync($"Executing task: {task.TaskName}");
|
|
|
|
|
|
// 执行任务逻辑
|
|
|
switch (task.TaskName)
|
|
|
{
|
|
|
case "ProductionCalculation":
|
|
|
await _productionService.CalculateAllProductionAsync();
|
|
|
break;
|
|
|
case "DataCollection":
|
|
|
// 数据采集逻辑
|
|
|
break;
|
|
|
case "LogArchival":
|
|
|
await _loggingService.ArchiveLogsAsync(30);
|
|
|
break;
|
|
|
case "DataCleanup":
|
|
|
// 数据清理逻辑
|
|
|
break;
|
|
|
default:
|
|
|
await _loggingService.LogWarningAsync($"Unknown task type: {task.TaskName}");
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
task.TaskStatus = TaskStatus.Completed;
|
|
|
task.CompletedAt = DateTime.Now;
|
|
|
await _taskRepository.UpdateAsync(task);
|
|
|
|
|
|
await _loggingService.LogInfoAsync($"Task {task.TaskName} completed successfully");
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
task.TaskStatus = TaskStatus.Failed;
|
|
|
task.ErrorMessage = ex.Message;
|
|
|
task.CompletedAt = DateTime.Now;
|
|
|
await _taskRepository.UpdateAsync(task);
|
|
|
|
|
|
await _loggingService.LogErrorAsync($"Task {task.TaskName} failed: {ex.Message}", ex);
|
|
|
}
|
|
|
finally
|
|
|
{
|
|
|
_runningTasks.TryRemove(taskId, out _);
|
|
|
_taskStatus.TryRemove(taskId, out _);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
_runningTasks[taskId] = taskExecution;
|
|
|
}
|
|
|
|
|
|
public async Task<TaskExecutionResult> GetTaskExecutionResultAsync(string taskId)
|
|
|
{
|
|
|
return await _taskRepository.GetLastExecutionResultAsync(taskId);
|
|
|
}
|
|
|
|
|
|
public async Task<bool> IsTaskRunningAsync(string taskId)
|
|
|
{
|
|
|
return _runningTasks.ContainsKey(taskId) && _taskStatus.ContainsKey(taskId) && _taskStatus[taskId];
|
|
|
}
|
|
|
|
|
|
public async Task<string> ScheduleRecurringTaskAsync(string taskName, Action taskAction, TimeSpan interval)
|
|
|
{
|
|
|
var task = new ScheduledTask
|
|
|
{
|
|
|
TaskId = Guid.NewGuid().ToString(),
|
|
|
TaskName = taskName,
|
|
|
CronExpression = $"*/{interval.TotalMinutes} * * * *",
|
|
|
TaskStatus = TaskStatus.Pending,
|
|
|
IsActive = true,
|
|
|
CreatedAt = DateTime.Now,
|
|
|
Description = $"Recurring task: {taskName}"
|
|
|
};
|
|
|
|
|
|
await ScheduleTaskAsync(task);
|
|
|
return task.TaskId;
|
|
|
}
|
|
|
|
|
|
private async Task CheckAndExecuteTasksAsync()
|
|
|
{
|
|
|
var pendingTasks = await _taskRepository.GetActiveTasksAsync();
|
|
|
var now = DateTime.Now;
|
|
|
|
|
|
foreach (var task in pendingTasks)
|
|
|
{
|
|
|
if (await ShouldExecuteTaskAsync(task, now))
|
|
|
{
|
|
|
await ExecuteTaskAsync(task.TaskId);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private async Task<bool> ShouldExecuteTaskAsync(ScheduledTask task, DateTime now)
|
|
|
{
|
|
|
if (task.TaskStatus == TaskStatus.Running || !task.IsActive)
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// 简单的时间检查(实际应该使用CRON表达式解析器)
|
|
|
if (task.LastRunAt == null)
|
|
|
{
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
var timeSinceLastRun = now - task.LastRunAt.Value;
|
|
|
return timeSinceLastRun.TotalMinutes >= 1; // 每分钟执行一次
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 缓存服务实现
|
|
|
public class CacheManager : ICachingService
|
|
|
{
|
|
|
private readonly ConcurrentDictionary<string, CacheItem> _cache = new();
|
|
|
private readonly System.Threading.Timer _cleanupTimer;
|
|
|
|
|
|
public CacheManager()
|
|
|
{
|
|
|
_cleanupTimer = new System.ThreadingTimer(
|
|
|
_ => CleanupExpiredItems(),
|
|
|
null,
|
|
|
TimeSpan.FromMinutes(5),
|
|
|
TimeSpan.FromMinutes(5));
|
|
|
}
|
|
|
|
|
|
public async Task<T> GetAsync<T>(string key)
|
|
|
{
|
|
|
if (_cache.TryGetValue(key, out var item))
|
|
|
{
|
|
|
if (item.ExpirationTime > DateTime.Now)
|
|
|
{
|
|
|
return (T)item.Value;
|
|
|
}
|
|
|
_cache.TryRemove(key, out _);
|
|
|
}
|
|
|
return default;
|
|
|
}
|
|
|
|
|
|
public async Task SetAsync<T>(string key, T value, TimeSpan? expiration = null)
|
|
|
{
|
|
|
var item = new CacheItem
|
|
|
{
|
|
|
Value = value,
|
|
|
ExpirationTime = DateTime.Now + (expiration ?? TimeSpan.FromMinutes(30))
|
|
|
};
|
|
|
|
|
|
_cache[key] = item;
|
|
|
}
|
|
|
|
|
|
public async Task<bool> RemoveAsync(string key)
|
|
|
{
|
|
|
return _cache.TryRemove(key, out _);
|
|
|
}
|
|
|
|
|
|
public async Task<bool> ExistsAsync(string key)
|
|
|
{
|
|
|
if (_cache.TryGetValue(key, out var item))
|
|
|
{
|
|
|
if (item.ExpirationTime > DateTime.Now)
|
|
|
{
|
|
|
return true;
|
|
|
}
|
|
|
_cache.TryRemove(key, out _);
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
public async Task ClearAsync()
|
|
|
{
|
|
|
_cache.Clear();
|
|
|
}
|
|
|
|
|
|
public async Task<T> GetOrCreateAsync<T>(string key, Func<Task<T>> factory, TimeSpan? expiration = null)
|
|
|
{
|
|
|
var value = await GetAsync<T>(key);
|
|
|
if (value == null)
|
|
|
{
|
|
|
value = await factory();
|
|
|
await SetAsync(key, value, expiration);
|
|
|
}
|
|
|
return value;
|
|
|
}
|
|
|
|
|
|
public async Task<IEnumerable<string>> GetAllKeysAsync()
|
|
|
{
|
|
|
return _cache.Keys;
|
|
|
}
|
|
|
|
|
|
public async Task<bool> RefreshAsync<T>(string key)
|
|
|
{
|
|
|
if (_cache.TryGetValue(key, out var item))
|
|
|
{
|
|
|
item.ExpirationTime = DateTime.Now + TimeSpan.FromMinutes(30);
|
|
|
return true;
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
private void CleanupExpiredItems()
|
|
|
{
|
|
|
var now = DateTime.Now;
|
|
|
var expiredKeys = _cache
|
|
|
.Where(kvp => kvp.Value.ExpirationTime <= now)
|
|
|
.Select(kvp => kvp.Key)
|
|
|
.ToList();
|
|
|
|
|
|
foreach (var key in expiredKeys)
|
|
|
{
|
|
|
_cache.TryRemove(key, out _);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private class CacheItem
|
|
|
{
|
|
|
public object Value { get; set; }
|
|
|
public DateTime ExpirationTime { get; set; }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 简化的JWT认证中间件
|
|
|
public class JwtAuthMiddleware : IWebSocketAuthMiddleware
|
|
|
{
|
|
|
private readonly IAuthService _authService;
|
|
|
private readonly ConcurrentDictionary<string, string> _connectionUsers = new();
|
|
|
|
|
|
public JwtAuthMiddleware(IAuthService authService)
|
|
|
{
|
|
|
_authService = authService;
|
|
|
}
|
|
|
|
|
|
public async Task AuthenticateAsync(string connectionId, string token)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
var isValid = await _authService.ValidateTokenAsync(token);
|
|
|
if (isValid)
|
|
|
{
|
|
|
var claims = await _authService.GetUserClaimsAsync(int.Parse(token));
|
|
|
_connectionUsers[connectionId] = claims.UserId.ToString();
|
|
|
}
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
// 认证失败
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public async Task<string> GetUserIdAsync(string connectionId)
|
|
|
{
|
|
|
_connectionUsers.TryGetValue(connectionId, out var userId);
|
|
|
return userId;
|
|
|
}
|
|
|
|
|
|
public async Task<string> GetConnectionIdAsync(string userId)
|
|
|
{
|
|
|
foreach (var kvp in _connectionUsers)
|
|
|
{
|
|
|
if (kvp.Value == userId)
|
|
|
{
|
|
|
return kvp.Key;
|
|
|
}
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
public async Task<bool> IsAuthenticatedAsync(string connectionId)
|
|
|
{
|
|
|
return _connectionUsers.ContainsKey(connectionId);
|
|
|
}
|
|
|
|
|
|
public async Task<bool> HasPermissionAsync(string connectionId, string permission)
|
|
|
{
|
|
|
var userId = await GetUserIdAsync(connectionId);
|
|
|
if (string.IsNullOrEmpty(userId))
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// 这里应该检查用户权限
|
|
|
return true; // 简化实现
|
|
|
}
|
|
|
}
|
|
|
} |