You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
272 lines
11 KiB
C#
272 lines
11 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Threading.Tasks;
|
|
using Haoliang.Models.Template;
|
|
using Haoliang.Models.Device;
|
|
using Haoliang.Models.DataCollection;
|
|
|
|
namespace Haoliang.Core.Services
|
|
{
|
|
public interface ITemplateService
|
|
{
|
|
Task<CNCBrandTemplate> CreateTemplateAsync(CNCBrandTemplate template);
|
|
Task<CNCBrandTemplate> UpdateTemplateAsync(int templateId, CNCBrandTemplate template);
|
|
Task<bool> DeleteTemplateAsync(int templateId);
|
|
Task<CNCBrandTemplate> GetTemplateByIdAsync(int templateId);
|
|
Task<IEnumerable<CNCBrandTemplate>> GetAllTemplatesAsync();
|
|
Task<IEnumerable<CNCBrandTemplate>> GetTemplatesByBrandAsync(string brandName);
|
|
Task<IEnumerable<CNCBrandTemplate>> GetActiveTemplatesAsync();
|
|
Task<bool> ValidateTemplateAsync(CNCBrandTemplate template);
|
|
Task TestTemplateAsync(int templateId);
|
|
Task<CNCBrandTemplate> CloneTemplateAsync(int templateId, string newName);
|
|
Task<bool> EnableTemplateAsync(int templateId);
|
|
Task<bool> DisableTemplateAsync(int templateId);
|
|
}
|
|
|
|
public interface ITagMappingService
|
|
{
|
|
Task<TagMapping> CreateTagMappingAsync(TagMapping mapping);
|
|
Task<TagMapping> UpdateTagMappingAsync(int mappingId, TagMapping mapping);
|
|
Task<bool> DeleteTagMappingAsync(int mappingId);
|
|
Task<TagMapping> GetTagMappingByIdAsync(int mappingId);
|
|
Task<IEnumerable<TagMapping>> GetAllTagMappingsAsync();
|
|
Task<IEnumerable<TagMapping>> GetMappingsByTemplateAsync(int templateId);
|
|
Task<TagMapping> MapDeviceTagAsync(TagData deviceTag, int templateId);
|
|
Task<Dictionary<string, TagData>> MapDeviceTagsAsync(IEnumerable<TagData> deviceTags, int templateId);
|
|
Task ValidateTagMappingAsync(TagMapping mapping);
|
|
}
|
|
|
|
public interface ITemplateValidationService
|
|
{
|
|
Task<bool> ValidateTemplateStructureAsync(CNCBrandTemplate template);
|
|
Task<bool> ValidateTagMappingsAsync(CNCBrandTemplate template);
|
|
Task<bool> ValidateDataParsingRulesAsync(CNCBrandTemplate template);
|
|
Task<IEnumerable<ValidationError>> ValidateTemplateForDeviceAsync(int templateId, int deviceId);
|
|
Task<bool> TestTemplateDataParsingAsync(CNCBrandTemplate template, string sampleData);
|
|
Task<IEnumerable<string>> GetMissingRequiredTagsAsync(CNCBrandTemplate template);
|
|
}
|
|
|
|
public interface ITemplateMigrationService
|
|
{
|
|
Task<CNCBrandTemplate> MigrateTemplateAsync(CNCBrandTemplate oldTemplate, string targetBrand);
|
|
Task<bool> ValidateMigrationCompatibilityAsync(CNCBrandTemplate sourceTemplate, string targetBrand);
|
|
Task<MigrationReport> GenerateMigrationReportAsync(CNCBrandTemplate template, string targetBrand);
|
|
Task<IEnumerable<MigrationIssue>> DetectMigrationIssuesAsync(CNCBrandTemplate template, string targetBrand);
|
|
}
|
|
|
|
public class TemplateManager : ITemplateService
|
|
{
|
|
private readonly ITemplateRepository _templateRepository;
|
|
private readonly ITagMappingService _tagMappingService;
|
|
private readonly ITemplateValidationService _validationService;
|
|
private readonly ITemplateMigrationService _migrationService;
|
|
|
|
public TemplateManager(
|
|
ITemplateRepository templateRepository,
|
|
ITagMappingService tagMappingService,
|
|
ITemplateValidationService validationService,
|
|
ITemplateMigrationService migrationService)
|
|
{
|
|
_templateRepository = templateRepository;
|
|
_tagMappingService = tagMappingService;
|
|
_validationService = validationService;
|
|
_migrationService = migrationService;
|
|
}
|
|
|
|
public async Task<CNCBrandTemplate> CreateTemplateAsync(CNCBrandTemplate template)
|
|
{
|
|
// 验证模板
|
|
var validationErrors = await _validationService.ValidateTemplateStructureAsync(template);
|
|
if (validationErrors.Count > 0)
|
|
{
|
|
throw new InvalidOperationException($"Template validation failed: {string.Join(", ", validationErrors)}");
|
|
}
|
|
|
|
// 设置初始状态
|
|
template.IsEnabled = true;
|
|
template.CreateTime = DateTime.Now;
|
|
template.UpdateTime = DateTime.Now;
|
|
|
|
var createdTemplate = await _templateRepository.AddAsync(template);
|
|
|
|
// 验证标签映射
|
|
await _validationService.ValidateTagMappingsAsync(createdTemplate);
|
|
|
|
return createdTemplate;
|
|
}
|
|
|
|
public async Task<CNCBrandTemplate> UpdateTemplateAsync(int templateId, CNCBrandTemplate template)
|
|
{
|
|
var existingTemplate = await _templateRepository.GetByIdAsync(templateId);
|
|
if (existingTemplate == null)
|
|
{
|
|
throw new KeyNotFoundException($"Template with ID {templateId} not found");
|
|
}
|
|
|
|
// 验证更新后的模板
|
|
var validationErrors = await _validationService.ValidateTemplateStructureAsync(template);
|
|
if (validationErrors.Count > 0)
|
|
{
|
|
throw new InvalidOperationException($"Template validation failed: {string.Join(", ", validationErrors)}");
|
|
}
|
|
|
|
template.TemplateId = templateId;
|
|
template.UpdateTime = DateTime.Now;
|
|
|
|
var updatedTemplate = await _templateRepository.UpdateAsync(template);
|
|
|
|
// 如果标签有变化,重新验证
|
|
if (HasTagMappingsChanged(existingTemplate, template))
|
|
{
|
|
await _validationService.ValidateTagMappingsAsync(updatedTemplate);
|
|
}
|
|
|
|
return updatedTemplate;
|
|
}
|
|
|
|
public async Task<bool> DeleteTemplateAsync(int templateId)
|
|
{
|
|
// 检查模板是否被使用
|
|
var isTemplateInUse = await _templateRepository.IsTemplateInUseAsync(templateId);
|
|
if (isTemplateInUse)
|
|
{
|
|
throw new InvalidOperationException("Cannot delete template that is currently in use by devices");
|
|
}
|
|
|
|
return await _templateRepository.DeleteAsync(templateId);
|
|
}
|
|
|
|
public async Task<CNCBrandTemplate> GetTemplateByIdAsync(int templateId)
|
|
{
|
|
return await _templateRepository.GetByIdAsync(templateId);
|
|
}
|
|
|
|
public async Task<IEnumerable<CNCBrandTemplate>> GetAllTemplatesAsync()
|
|
{
|
|
return await _templateRepository.GetAllAsync();
|
|
}
|
|
|
|
public async Task<IEnumerable<CNCBrandTemplate>> GetTemplatesByBrandAsync(string brandName)
|
|
{
|
|
return await _templateRepository.GetByBrandAsync(brandName);
|
|
}
|
|
|
|
public async Task<IEnumerable<CNCBrandTemplate>> GetActiveTemplatesAsync()
|
|
{
|
|
return await _templateRepository.GetActiveTemplatesAsync();
|
|
}
|
|
|
|
public async Task<bool> ValidateTemplateAsync(CNCBrandTemplate template)
|
|
{
|
|
return await _validationService.ValidateTemplateStructureAsync(template);
|
|
}
|
|
|
|
public async Task TestTemplateAsync(int templateId)
|
|
{
|
|
var template = await _templateRepository.GetByIdAsync(templateId);
|
|
if (template == null)
|
|
{
|
|
throw new KeyNotFoundException($"Template with ID {templateId} not found");
|
|
}
|
|
|
|
// 使用模板进行数据解析测试
|
|
await _validationService.TestTemplateDataParsingAsync(template, GetSampleData(template));
|
|
}
|
|
|
|
public async Task<CNCBrandTemplate> CloneTemplateAsync(int templateId, string newName)
|
|
{
|
|
var originalTemplate = await _templateRepository.GetByIdAsync(templateId);
|
|
if (originalTemplate == null)
|
|
{
|
|
throw new KeyNotFoundException($"Template with ID {templateId} not found");
|
|
}
|
|
|
|
var clonedTemplate = new CNCBrandTemplate
|
|
{
|
|
TemplateName = newName,
|
|
BrandName = originalTemplate.BrandName,
|
|
Description = $"Cloned from {originalTemplate.TemplateName}",
|
|
IsEnabled = false, // 新克隆的模板默认禁用
|
|
Version = originalTemplate.Version,
|
|
TemplateJson = originalTemplate.TemplateJson,
|
|
CreateTime = DateTime.Now,
|
|
UpdateTime = DateTime.Now
|
|
};
|
|
|
|
return await CreateTemplateAsync(clonedTemplate);
|
|
}
|
|
|
|
public async Task<bool> EnableTemplateAsync(int templateId)
|
|
{
|
|
var template = await _templateRepository.GetByIdAsync(templateId);
|
|
if (template == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
template.IsEnabled = true;
|
|
template.UpdateTime = DateTime.Now;
|
|
|
|
return await _templateRepository.UpdateAsync(template) != null;
|
|
}
|
|
|
|
public async Task<bool> DisableTemplateAsync(int templateId)
|
|
{
|
|
var template = await _templateRepository.GetByIdAsync(templateId);
|
|
if (template == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// 检查是否还有设备在使用此模板
|
|
var isTemplateInUse = await _templateRepository.IsTemplateInUseAsync(templateId);
|
|
if (isTemplateInUse)
|
|
{
|
|
throw new InvalidOperationException("Cannot disable template that is currently in use by devices");
|
|
}
|
|
|
|
template.IsEnabled = false;
|
|
template.UpdateTime = DateTime.Now;
|
|
|
|
return await _templateRepository.UpdateAsync(template) != null;
|
|
}
|
|
|
|
private bool HasTagMappingsChanged(CNCBrandTemplate oldTemplate, CNCBrandTemplate newTemplate)
|
|
{
|
|
// 简单比较JSON内容是否变化
|
|
return oldTemplate.TemplateJson != newTemplate.TemplateJson;
|
|
}
|
|
|
|
private string GetSampleData(CNCBrandTemplate template)
|
|
{
|
|
// 返回模拟的设备数据用于测试
|
|
return @"{
|
|
""device"": ""FANUC_01"",
|
|
""desc"": ""CNC Machine"",
|
|
""tags"": [
|
|
{
|
|
""id"": ""_io_status"",
|
|
""desc"": ""I/O Status"",
|
|
""quality"": 0,
|
|
""value"": 1,
|
|
""time"": ""2024-01-01T10:00:00""
|
|
},
|
|
{
|
|
""id"": ""Tag5"",
|
|
""desc"": ""NC Program"",
|
|
""quality"": 0,
|
|
""value"": ""O1234"",
|
|
""time"": ""2024-01-01T10:00:00""
|
|
},
|
|
{
|
|
""id"": ""Tag8"",
|
|
""desc"": ""Cumulative Count"",
|
|
""quality"": 0,
|
|
""value"": 12345.00000,
|
|
""time"": ""2024-01-01T10:00:00""
|
|
}
|
|
]
|
|
}";
|
|
}
|
|
}
|
|
} |