using System; using System.Collections.Generic; using System.Threading.Tasks; using System.Text.RegularExpressions; using System.Linq; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using ZhonTai.Admin.Services; using ZhonTai.DynamicApi; using ZhonTai.DynamicApi.Attributes; using NPP.SmartSchedue.Api.Contracts.Services.Notification; using NPP.SmartSchedue.Api.Contracts.Services.Notification.Input; using NPP.SmartSchedue.Api.Contracts.Services.Notification.Output; namespace NPP.SmartSchedue.Api.Services.Notification; /// /// 通知服务 模板 /// [DynamicApi(Area = "app")] public class NotificationTemplateService : BaseService, INotificationTemplateService, IDynamicApi { // 变量匹配正则表达式:匹配 {变量名} 格式 private static readonly Regex VariableRegex = new Regex(@"\{([a-zA-Z_][a-zA-Z0-9_]*)\}", RegexOptions.Compiled); #region 模板渲染 /// /// 渲染通知模板 /// 支持变量替换,如:{变量名} /// /// 渲染模板输入参数 /// 渲染结果 [HttpPost] public async Task RenderTemplateAsync(RenderTemplateInput input) { try { var renderedContent = RenderTemplateCore(input.Template, input.Variables); return await Task.FromResult(new RenderTemplateOutput { RenderedContent = renderedContent, Success = true }); } catch (Exception ex) { return new RenderTemplateOutput { Success = false, ErrorMessage = $"渲染模板时发生错误:{ex.Message}" }; } } #endregion #region 模板验证 /// /// 验证模板语法是否正确 /// /// 验证模板输入参数 /// 验证结果 [HttpPost] public async Task ValidateTemplateAsync(ValidateTemplateInput input) { try { var validationResult = ValidateTemplateCore(input.Template); return await Task.FromResult(new ValidateTemplateOutput { ValidationResult = validationResult, Success = true }); } catch (Exception ex) { return new ValidateTemplateOutput { Success = false, ErrorMessage = $"验证模板时发生错误:{ex.Message}", ValidationResult = new TemplateValidationResult() }; } } #endregion #region 变量解析 /// /// 提取模板中的变量列表 /// /// 提取变量输入参数 /// 变量列表 [HttpPost] public async Task ExtractVariablesAsync(ExtractVariablesInput input) { try { var variables = ExtractVariablesCore(input.Template); return await Task.FromResult(new ExtractVariablesOutput { Variables = variables, Success = true }); } catch (Exception ex) { return new ExtractVariablesOutput { Success = false, ErrorMessage = $"提取变量时发生错误:{ex.Message}" }; } } #endregion #region 内置变量 /// /// 获取系统内置变量 /// /// 系统变量字典 [HttpPost] public async Task GetSystemVariablesAsync() { try { var systemVariables = GetSystemVariablesCore(); return await Task.FromResult(new GetSystemVariablesOutput { Variables = systemVariables, Success = true }); } catch (Exception ex) { return new GetSystemVariablesOutput { Success = false, ErrorMessage = $"获取系统变量时发生错误:{ex.Message}" }; } } /// /// 获取业务相关变量 /// /// 获取业务变量输入参数 /// 业务变量字典 [HttpPost] public async Task GetBusinessVariablesAsync(GetBusinessVariablesInput input) { try { var businessVariables = await GetBusinessVariablesCore(input.BusinessType, input.BusinessId, input.BusinessData); return new GetBusinessVariablesOutput { Variables = businessVariables, Success = true }; } catch (Exception ex) { return new GetBusinessVariablesOutput { Success = false, ErrorMessage = $"获取业务变量时发生错误:{ex.Message}" }; } } #endregion #region 模板预定义 /// /// 获取预定义模板列表 /// /// 获取模板列表输入参数 /// 预定义模板列表 [HttpPost] public async Task GetPredefinedTemplatesAsync(GetPredefinedTemplatesInput input) { try { var templates = GetDefaultPredefinedTemplates(); if (!string.IsNullOrWhiteSpace(input.Category)) { templates = templates.Where(t => string.Equals(t.Category, input.Category, StringComparison.OrdinalIgnoreCase)).ToList(); } return await Task.FromResult(new GetPredefinedTemplatesOutput { Templates = templates, TotalCount = templates.Count, Success = true }); } catch (Exception ex) { return new GetPredefinedTemplatesOutput { Success = false, ErrorMessage = $"获取预定义模板列表时发生错误:{ex.Message}" }; } } /// /// 获取指定预定义模板 /// /// 获取指定模板输入参数 /// 预定义模板 [HttpPost] public async Task GetPredefinedTemplateAsync(GetPredefinedTemplateInput input) { try { var templates = GetDefaultPredefinedTemplates(); var template = templates.FirstOrDefault(t => string.Equals(t.TemplateId, input.TemplateId, StringComparison.OrdinalIgnoreCase)); return await Task.FromResult(new GetPredefinedTemplateOutput { Template = template, Success = true }); } catch (Exception ex) { return new GetPredefinedTemplateOutput { Success = false, ErrorMessage = $"获取指定预定义模板时发生错误:{ex.Message}" }; } } #endregion #region 核心业务逻辑方法 /// /// 核心模板渲染逻辑 /// /// 模板内容 /// 变量字典 /// 渲染后的内容 private string RenderTemplateCore(string template, Dictionary variables) { if (string.IsNullOrWhiteSpace(template)) return string.Empty; if (variables == null || !variables.Any()) return template; var result = template; // 替换所有匹配的变量 result = VariableRegex.Replace(result, match => { var variableName = match.Groups[1].Value; // 如果变量存在于字典中,则替换 if (variables.TryGetValue(variableName, out var variableValue)) { return variableValue ?? string.Empty; } // 如果变量不存在,保留原始占位符 return match.Value; }); return result; } /// /// 核心模板验证逻辑 /// /// 模板内容 /// 验证结果 private TemplateValidationResult ValidateTemplateCore(string template) { var result = new TemplateValidationResult(); if (string.IsNullOrWhiteSpace(template)) { result.AddError("模板内容不能为空"); return result; } try { // 提取所有变量 var variables = ExtractVariablesCore(template); result.Variables = variables; // 检查变量命名规范 foreach (var variable in variables) { if (!IsValidVariableName(variable)) { result.AddError($"变量名 '{variable}' 不符合命名规范,变量名只能包含字母、数字和下划线,且不能以数字开头"); } } // 检查是否有未闭合的大括号 var openBraceCount = template.Count(c => c == '{'); var closeBraceCount = template.Count(c => c == '}'); if (openBraceCount != closeBraceCount) { result.AddError($"大括号不匹配:找到 {openBraceCount} 个左大括号和 {closeBraceCount} 个右大括号"); } // 检查嵌套大括号 if (template.Contains("{{") || template.Contains("}}")) { result.AddWarning("发现嵌套大括号,这可能导致变量替换异常"); } // 检查空的变量占位符 if (template.Contains("{}")) { result.AddError("发现空的变量占位符 {},请指定变量名"); } } catch (Exception ex) { result.AddError($"模板验证时发生异常:{ex.Message}"); } return result; } /// /// 核心变量提取逻辑 /// /// 模板内容 /// 变量名列表 private List ExtractVariablesCore(string template) { if (string.IsNullOrWhiteSpace(template)) return new List(); var variables = new HashSet(); var matches = VariableRegex.Matches(template); foreach (Match match in matches) { var variableName = match.Groups[1].Value; variables.Add(variableName); } return variables.OrderBy(v => v).ToList(); } /// /// 获取系统内置变量核心逻辑 /// /// 系统变量字典 private Dictionary GetSystemVariablesCore() { var now = DateTime.Now; return new Dictionary { ["CurrentDateTime"] = now.ToString("yyyy-MM-dd HH:mm:ss"), ["CurrentDate"] = now.ToString("yyyy-MM-dd"), ["CurrentTime"] = now.ToString("HH:mm:ss"), ["CurrentYear"] = now.Year.ToString(), ["CurrentMonth"] = now.Month.ToString(), ["CurrentDay"] = now.Day.ToString(), ["CurrentWeekday"] = GetWeekdayName(now.DayOfWeek), ["SystemName"] = "NPP智能生产调度系统", ["CompanyName"] = "核电站" }; } /// /// 获取业务相关变量核心逻辑 /// /// 业务类型 /// 业务ID /// 业务数据 /// 业务变量字典 private async Task> GetBusinessVariablesCore( string businessType, long? businessId, string businessData) { var businessVariables = new Dictionary { ["BusinessType"] = businessType ?? "", ["BusinessId"] = businessId?.ToString() ?? "" }; // 根据业务类型添加特定变量 switch (businessType?.ToLower()) { case "workorder": case "工作任务": await AddWorkOrderVariablesAsync(businessVariables, businessId, businessData); break; case "equipment": case "设备": await AddEquipmentVariablesAsync(businessVariables, businessId, businessData); break; case "personnel": case "人员": await AddPersonnelVariablesAsync(businessVariables, businessId, businessData); break; case "maintenance": case "维护": await AddMaintenanceVariablesAsync(businessVariables, businessId, businessData); break; } return businessVariables; } #endregion #region 私有辅助方法 /// /// 验证变量名是否符合规范 /// /// 变量名 /// 是否符合规范 private static bool IsValidVariableName(string variableName) { if (string.IsNullOrWhiteSpace(variableName)) return false; // 变量名只能包含字母、数字和下划线,且不能以数字开头 return Regex.IsMatch(variableName, @"^[a-zA-Z_][a-zA-Z0-9_]*$"); } /// /// 获取星期几的中文名称 /// /// 星期枚举 /// 中文名称 private static string GetWeekdayName(DayOfWeek dayOfWeek) { return dayOfWeek switch { DayOfWeek.Monday => "星期一", DayOfWeek.Tuesday => "星期二", DayOfWeek.Wednesday => "星期三", DayOfWeek.Thursday => "星期四", DayOfWeek.Friday => "星期五", DayOfWeek.Saturday => "星期六", DayOfWeek.Sunday => "星期日", _ => "" }; } /// /// 添加工作任务相关变量 /// /// 变量字典 /// 业务ID /// 业务数据 /// 异步任务 private async Task AddWorkOrderVariablesAsync(Dictionary variables, long? businessId, string businessData) { // 这里可以根据businessId查询工作任务详情,然后添加相关变量 // 为了简化示例,先添加一些基础变量 variables["WorkOrderId"] = businessId?.ToString() ?? ""; if (!string.IsNullOrWhiteSpace(businessData)) { try { var data = JsonConvert.DeserializeObject>(businessData); if (data != null) { foreach (var item in data) { variables[$"WorkOrder_{item.Key}"] = item.Value?.ToString() ?? ""; } } } catch (JsonException) { // 忽略JSON解析错误 } } await Task.CompletedTask; } /// /// 添加设备相关变量 /// /// 变量字典 /// 业务ID /// 业务数据 /// 异步任务 private async Task AddEquipmentVariablesAsync(Dictionary variables, long? businessId, string businessData) { variables["EquipmentId"] = businessId?.ToString() ?? ""; // 可以添加更多设备相关变量 await Task.CompletedTask; } /// /// 添加人员相关变量 /// /// 变量字典 /// 业务ID /// 业务数据 /// 异步任务 private async Task AddPersonnelVariablesAsync(Dictionary variables, long? businessId, string businessData) { variables["PersonnelId"] = businessId?.ToString() ?? ""; // 可以添加更多人员相关变量 await Task.CompletedTask; } /// /// 添加维护相关变量 /// /// 变量字典 /// 业务ID /// 业务数据 /// 异步任务 private async Task AddMaintenanceVariablesAsync(Dictionary variables, long? businessId, string businessData) { variables["MaintenanceId"] = businessId?.ToString() ?? ""; // 可以添加更多维护相关变量 await Task.CompletedTask; } /// /// 获取默认预定义模板 /// /// 预定义模板列表 private static List GetDefaultPredefinedTemplates() { return new List { new PredefinedTemplate { TemplateId = "work_order_assignment", TemplateName = "工作任务分配通知", Category = "工作任务", Description = "当工作任务被分配给人员时发送的通知", EmailSubjectTemplate = "工作任务分配通知 - {WorkOrderCode}", EmailContentTemplate = @"

工作任务分配通知

您好,{PersonnelName}!

有新的工作任务分配给您:

  • 任务代码:{WorkOrderCode}
  • 项目号:{ProjectNumber}
  • 工序名称:{ProcessName}
  • 计划开始时间:{PlannedStartTime}
  • 计划结束时间:{PlannedEndTime}

请及时查看并开始执行任务。

系统时间:{CurrentDateTime}

", SystemMessageTitleTemplate = "新任务分配 - {WorkOrderCode}", SystemMessageContentTemplate = "您有新的工作任务:{WorkOrderCode},请及时处理。", SupportedVariables = new List { new TemplateVariable { Name = "PersonnelName", Description = "人员姓名", IsRequired = true }, new TemplateVariable { Name = "WorkOrderCode", Description = "任务代码", IsRequired = true }, new TemplateVariable { Name = "ProjectNumber", Description = "项目号", IsRequired = true }, new TemplateVariable { Name = "ProcessName", Description = "工序名称", IsRequired = true }, new TemplateVariable { Name = "PlannedStartTime", Description = "计划开始时间", IsRequired = true }, new TemplateVariable { Name = "PlannedEndTime", Description = "计划结束时间", IsRequired = true } } }, new PredefinedTemplate { TemplateId = "equipment_maintenance_reminder", TemplateName = "设备维护提醒", Category = "设备维护", Description = "设备维护到期提醒通知", EmailSubjectTemplate = "设备维护提醒 - {EquipmentName}", EmailContentTemplate = @"

设备维护提醒

您好,{PersonnelName}!

以下设备需要进行维护:

  • 设备名称:{EquipmentName}
  • 设备编号:{EquipmentCode}
  • 计划维护时间:{PlannedMaintenanceTime}
  • 维护类型:{MaintenanceType}

请及时安排维护工作。

系统时间:{CurrentDateTime}

", SystemMessageTitleTemplate = "设备维护提醒 - {EquipmentName}", SystemMessageContentTemplate = "设备 {EquipmentName} 需要维护,计划时间:{PlannedMaintenanceTime}", SupportedVariables = new List { new TemplateVariable { Name = "PersonnelName", Description = "人员姓名", IsRequired = true }, new TemplateVariable { Name = "EquipmentName", Description = "设备名称", IsRequired = true }, new TemplateVariable { Name = "EquipmentCode", Description = "设备编号", IsRequired = true }, new TemplateVariable { Name = "PlannedMaintenanceTime", Description = "计划维护时间", IsRequired = true }, new TemplateVariable { Name = "MaintenanceType", Description = "维护类型", IsRequired = false } } } }; } #endregion }