627 lines
22 KiB
C#
627 lines
22 KiB
C#
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;
|
||
|
||
/// <summary>
|
||
/// 通知服务 模板
|
||
/// </summary>
|
||
[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 模板渲染
|
||
|
||
/// <summary>
|
||
/// 渲染通知模板
|
||
/// 支持变量替换,如:{变量名}
|
||
/// </summary>
|
||
/// <param name="input">渲染模板输入参数</param>
|
||
/// <returns>渲染结果</returns>
|
||
[HttpPost]
|
||
public async Task<RenderTemplateOutput> 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 模板验证
|
||
|
||
/// <summary>
|
||
/// 验证模板语法是否正确
|
||
/// </summary>
|
||
/// <param name="input">验证模板输入参数</param>
|
||
/// <returns>验证结果</returns>
|
||
[HttpPost]
|
||
public async Task<ValidateTemplateOutput> 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 变量解析
|
||
|
||
/// <summary>
|
||
/// 提取模板中的变量列表
|
||
/// </summary>
|
||
/// <param name="input">提取变量输入参数</param>
|
||
/// <returns>变量列表</returns>
|
||
[HttpPost]
|
||
public async Task<ExtractVariablesOutput> 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 内置变量
|
||
|
||
/// <summary>
|
||
/// 获取系统内置变量
|
||
/// </summary>
|
||
/// <returns>系统变量字典</returns>
|
||
[HttpPost]
|
||
public async Task<GetSystemVariablesOutput> 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}"
|
||
};
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取业务相关变量
|
||
/// </summary>
|
||
/// <param name="input">获取业务变量输入参数</param>
|
||
/// <returns>业务变量字典</returns>
|
||
[HttpPost]
|
||
public async Task<GetBusinessVariablesOutput> 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 模板预定义
|
||
|
||
/// <summary>
|
||
/// 获取预定义模板列表
|
||
/// </summary>
|
||
/// <param name="input">获取模板列表输入参数</param>
|
||
/// <returns>预定义模板列表</returns>
|
||
[HttpPost]
|
||
public async Task<GetPredefinedTemplatesOutput> 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}"
|
||
};
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取指定预定义模板
|
||
/// </summary>
|
||
/// <param name="input">获取指定模板输入参数</param>
|
||
/// <returns>预定义模板</returns>
|
||
[HttpPost]
|
||
public async Task<GetPredefinedTemplateOutput> 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 核心业务逻辑方法
|
||
|
||
/// <summary>
|
||
/// 核心模板渲染逻辑
|
||
/// </summary>
|
||
/// <param name="template">模板内容</param>
|
||
/// <param name="variables">变量字典</param>
|
||
/// <returns>渲染后的内容</returns>
|
||
private string RenderTemplateCore(string template, Dictionary<string, string> 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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 核心模板验证逻辑
|
||
/// </summary>
|
||
/// <param name="template">模板内容</param>
|
||
/// <returns>验证结果</returns>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 核心变量提取逻辑
|
||
/// </summary>
|
||
/// <param name="template">模板内容</param>
|
||
/// <returns>变量名列表</returns>
|
||
private List<string> ExtractVariablesCore(string template)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(template))
|
||
return new List<string>();
|
||
|
||
var variables = new HashSet<string>();
|
||
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();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取系统内置变量核心逻辑
|
||
/// </summary>
|
||
/// <returns>系统变量字典</returns>
|
||
private Dictionary<string, string> GetSystemVariablesCore()
|
||
{
|
||
var now = DateTime.Now;
|
||
|
||
return new Dictionary<string, string>
|
||
{
|
||
["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"] = "核电站"
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取业务相关变量核心逻辑
|
||
/// </summary>
|
||
/// <param name="businessType">业务类型</param>
|
||
/// <param name="businessId">业务ID</param>
|
||
/// <param name="businessData">业务数据</param>
|
||
/// <returns>业务变量字典</returns>
|
||
private async Task<Dictionary<string, string>> GetBusinessVariablesCore(
|
||
string businessType,
|
||
long? businessId,
|
||
string businessData)
|
||
{
|
||
var businessVariables = new Dictionary<string, string>
|
||
{
|
||
["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 私有辅助方法
|
||
|
||
/// <summary>
|
||
/// 验证变量名是否符合规范
|
||
/// </summary>
|
||
/// <param name="variableName">变量名</param>
|
||
/// <returns>是否符合规范</returns>
|
||
private static bool IsValidVariableName(string variableName)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(variableName))
|
||
return false;
|
||
|
||
// 变量名只能包含字母、数字和下划线,且不能以数字开头
|
||
return Regex.IsMatch(variableName, @"^[a-zA-Z_][a-zA-Z0-9_]*$");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取星期几的中文名称
|
||
/// </summary>
|
||
/// <param name="dayOfWeek">星期枚举</param>
|
||
/// <returns>中文名称</returns>
|
||
private static string GetWeekdayName(DayOfWeek dayOfWeek)
|
||
{
|
||
return dayOfWeek switch
|
||
{
|
||
DayOfWeek.Monday => "星期一",
|
||
DayOfWeek.Tuesday => "星期二",
|
||
DayOfWeek.Wednesday => "星期三",
|
||
DayOfWeek.Thursday => "星期四",
|
||
DayOfWeek.Friday => "星期五",
|
||
DayOfWeek.Saturday => "星期六",
|
||
DayOfWeek.Sunday => "星期日",
|
||
_ => ""
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加工作任务相关变量
|
||
/// </summary>
|
||
/// <param name="variables">变量字典</param>
|
||
/// <param name="businessId">业务ID</param>
|
||
/// <param name="businessData">业务数据</param>
|
||
/// <returns>异步任务</returns>
|
||
private async Task AddWorkOrderVariablesAsync(Dictionary<string, string> variables, long? businessId, string businessData)
|
||
{
|
||
// 这里可以根据businessId查询工作任务详情,然后添加相关变量
|
||
// 为了简化示例,先添加一些基础变量
|
||
variables["WorkOrderId"] = businessId?.ToString() ?? "";
|
||
|
||
if (!string.IsNullOrWhiteSpace(businessData))
|
||
{
|
||
try
|
||
{
|
||
var data = JsonConvert.DeserializeObject<Dictionary<string, object>>(businessData);
|
||
if (data != null)
|
||
{
|
||
foreach (var item in data)
|
||
{
|
||
variables[$"WorkOrder_{item.Key}"] = item.Value?.ToString() ?? "";
|
||
}
|
||
}
|
||
}
|
||
catch (JsonException)
|
||
{
|
||
// 忽略JSON解析错误
|
||
}
|
||
}
|
||
|
||
await Task.CompletedTask;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加设备相关变量
|
||
/// </summary>
|
||
/// <param name="variables">变量字典</param>
|
||
/// <param name="businessId">业务ID</param>
|
||
/// <param name="businessData">业务数据</param>
|
||
/// <returns>异步任务</returns>
|
||
private async Task AddEquipmentVariablesAsync(Dictionary<string, string> variables, long? businessId, string businessData)
|
||
{
|
||
variables["EquipmentId"] = businessId?.ToString() ?? "";
|
||
// 可以添加更多设备相关变量
|
||
await Task.CompletedTask;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加人员相关变量
|
||
/// </summary>
|
||
/// <param name="variables">变量字典</param>
|
||
/// <param name="businessId">业务ID</param>
|
||
/// <param name="businessData">业务数据</param>
|
||
/// <returns>异步任务</returns>
|
||
private async Task AddPersonnelVariablesAsync(Dictionary<string, string> variables, long? businessId, string businessData)
|
||
{
|
||
variables["PersonnelId"] = businessId?.ToString() ?? "";
|
||
// 可以添加更多人员相关变量
|
||
await Task.CompletedTask;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加维护相关变量
|
||
/// </summary>
|
||
/// <param name="variables">变量字典</param>
|
||
/// <param name="businessId">业务ID</param>
|
||
/// <param name="businessData">业务数据</param>
|
||
/// <returns>异步任务</returns>
|
||
private async Task AddMaintenanceVariablesAsync(Dictionary<string, string> variables, long? businessId, string businessData)
|
||
{
|
||
variables["MaintenanceId"] = businessId?.ToString() ?? "";
|
||
// 可以添加更多维护相关变量
|
||
await Task.CompletedTask;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取默认预定义模板
|
||
/// </summary>
|
||
/// <returns>预定义模板列表</returns>
|
||
private static List<PredefinedTemplate> GetDefaultPredefinedTemplates()
|
||
{
|
||
return new List<PredefinedTemplate>
|
||
{
|
||
new PredefinedTemplate
|
||
{
|
||
TemplateId = "work_order_assignment",
|
||
TemplateName = "工作任务分配通知",
|
||
Category = "工作任务",
|
||
Description = "当工作任务被分配给人员时发送的通知",
|
||
EmailSubjectTemplate = "工作任务分配通知 - {WorkOrderCode}",
|
||
EmailContentTemplate = @"
|
||
<div>
|
||
<h3>工作任务分配通知</h3>
|
||
<p>您好,{PersonnelName}!</p>
|
||
<p>有新的工作任务分配给您:</p>
|
||
<ul>
|
||
<li>任务代码:{WorkOrderCode}</li>
|
||
<li>项目号:{ProjectNumber}</li>
|
||
<li>工序名称:{ProcessName}</li>
|
||
<li>计划开始时间:{PlannedStartTime}</li>
|
||
<li>计划结束时间:{PlannedEndTime}</li>
|
||
</ul>
|
||
<p>请及时查看并开始执行任务。</p>
|
||
<p>系统时间:{CurrentDateTime}</p>
|
||
</div>
|
||
",
|
||
SystemMessageTitleTemplate = "新任务分配 - {WorkOrderCode}",
|
||
SystemMessageContentTemplate = "您有新的工作任务:{WorkOrderCode},请及时处理。",
|
||
SupportedVariables = new List<TemplateVariable>
|
||
{
|
||
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 = @"
|
||
<div>
|
||
<h3>设备维护提醒</h3>
|
||
<p>您好,{PersonnelName}!</p>
|
||
<p>以下设备需要进行维护:</p>
|
||
<ul>
|
||
<li>设备名称:{EquipmentName}</li>
|
||
<li>设备编号:{EquipmentCode}</li>
|
||
<li>计划维护时间:{PlannedMaintenanceTime}</li>
|
||
<li>维护类型:{MaintenanceType}</li>
|
||
</ul>
|
||
<p>请及时安排维护工作。</p>
|
||
<p>系统时间:{CurrentDateTime}</p>
|
||
</div>
|
||
",
|
||
SystemMessageTitleTemplate = "设备维护提醒 - {EquipmentName}",
|
||
SystemMessageContentTemplate = "设备 {EquipmentName} 需要维护,计划时间:{PlannedMaintenanceTime}",
|
||
SupportedVariables = new List<TemplateVariable>
|
||
{
|
||
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
|
||
} |