using System.Collections.Concurrent;
using DS.Module.Core;
using DS.Module.Core.Data;
using DS.Module.PrintModule;
using DS.WMS.Core.Code.Entity;
using DS.WMS.Core.Info.Entity;
using DS.WMS.Core.Op.Dtos.TaskInteraction;
using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Op.Entity.TaskInteraction;
using DS.WMS.Core.Op.Interface;
using DS.WMS.Core.Op.Interface.TaskInteraction;
using DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor;
using DS.WMS.Core.Op.Method.TaskInteraction.ActionExecutor.Booking;
using DS.WMS.Core.Sys.Entity;
using HtmlAgilityPack;
using Mapster;
using Masuit.Tools;
using Masuit.Tools.Systems;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using RazorEngineCore;
namespace DS.WMS.Core.Op.Method.TaskInteraction
{
///
/// 业务邮件发送服务
///
public class MailService : ServiceBase
{
static readonly ConcurrentDictionary TemplateCache =
new ConcurrentDictionary();
ITaskMailService service;
ISeaExportService seService;
IConfiguration config;
ApiFox Api = DefaultActionExecutor.Api;
///
/// 初始化
///
///
public MailService(IServiceProvider provider) : base(provider)
{
service = provider.GetRequiredService();
seService = provider.GetRequiredService();
config = provider.GetRequiredService();
}
private async Task RenderTemplateAsync(string name, string templateText, object model, RazorEngine? razorEngine = null)
{
int hashCode = name.GetHashCode();
IRazorEngineCompiledTemplate compiledTemplate = TemplateCache.GetOrAdd(hashCode, i =>
{
var engine = razorEngine ?? new RazorEngine();
return engine.Compile(templateText);
});
return await compiledTemplate.RunAsync(model);
}
///
/// 根据配置发送邮件
///
/// 邮件配置
/// 业务ID
/// 业务类型
///
public async Task SendAsync(BusinessTaskMail mailConfig,
long businessId, BusinessType businessType = BusinessType.OceanShippingExport)
{
ArgumentNullException.ThrowIfNull(mailConfig, nameof(mailConfig));
var result = seService.GetSeaExportInfo(businessId.ToString());
if (!result.Succeeded || result.Data == null)
return DataResult.Failed($"未能获取Id={businessId}的{businessType.GetDescription()}数据");
string title, content = string.Empty;
var templateModel = new MailTemplateModel { Primary = result.Data.Adapt() };
var razorEngine = new RazorEngine();
try
{
string key1 = mailConfig.Id + "-" + nameof(mailConfig.Title);
title = await RenderTemplateAsync(key1, mailConfig.Title, templateModel, razorEngine);
string key2 = mailConfig.Id + "-" + nameof(mailConfig.Content);
content = await RenderTemplateAsync(key2, mailConfig.Content, templateModel, razorEngine);
}
catch (Exception ex)
{
await ex.LogAsync(Db);
return DataResult.Failed($"渲染邮件模板({mailConfig.Id})时出错,请检查模板是否有语法错误");
}
//设置发件人
long senderId = 0;
if (mailConfig.Sender.IsSale)
senderId = templateModel.Primary.SaleId;
else if (mailConfig.Sender.IsOperator)
senderId = templateModel.Primary.OperatorId;
else if (mailConfig.Sender.IsCustomerService)
senderId = templateModel.Primary.CustomerService;
else if (mailConfig.Sender.IsVouchingClerk)
senderId = templateModel.Primary.Doc;
var sender = await Db.Queryable().Where(x => x.Id == senderId).Select(x => new { x.UserName, x.SignatureHtml }).FirstAsync();
if (sender == null)
return DataResult.Failed("未设置发件人");
var senderConfig = await TenantDb.Queryable().FirstAsync(x => x.CreateBy == senderId);
if (senderConfig == null)
return DataResult.Failed($"发件人用户:{sender.UserName} 未设置SMTP发件信息");
//插入发件人签名
var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(content);
var node = htmlDoc.GetElementbyId("sign");
if (node != null)
node.InnerHtml = sender.SignatureHtml;
using (StringWriter writer = new())
{
htmlDoc.Save(writer);
content = writer.ToString();
writer.Close();
}
//设置抄送人
List ccIds = [];
List ccList = [];
if (mailConfig.CC.IsSale)
ccIds.Add(templateModel.Primary.SaleId);
else if (mailConfig.CC.IsOperator)
ccIds.Add(templateModel.Primary.OperatorId);
else if (mailConfig.CC.IsCustomerService)
ccIds.Add(templateModel.Primary.CustomerService);
else if (mailConfig.CC.IsVouchingClerk)
ccIds.Add(templateModel.Primary.Doc);
if (ccIds.Count > 0)
ccList = await Db.Queryable().Where(x => ccIds.Contains(x.Id)).Select(x => x.Email).ToListAsync();
//设置收件人
List receiverIds = [];
if (mailConfig.Receiver.IsCarrier)
receiverIds.Add(templateModel.Primary.CarrierId);
if (mailConfig.Receiver.IsBooking)
receiverIds.Add(templateModel.Primary.ForwarderId);
if (mailConfig.Receiver.IsYard)
receiverIds.Add(templateModel.Primary.YardId);
if (mailConfig.Receiver.IsTruck)
receiverIds.Add(templateModel.Primary.TruckerId);
if (mailConfig.Receiver.IsController)
receiverIds.Add(templateModel.Primary.CustomerId);
var receiverList = await TenantDb.Queryable().Where(x => receiverIds.Contains(x.Id) && x.Email != null && x.Email != string.Empty)
.Select(x => new { x.ShortName, x.EnShortName, x.Email }).ToListAsync();
var attachmentList = mailConfig.Attachments == null ? [] : new List>(mailConfig.Attachments.Count);
try
{
//需要上传附件
if (mailConfig.Attachments?.Count > 0)
{
if (Api.DefaultHeaders.Contains("Authorization"))
Api.DefaultHeaders.Remove("Authorization");
Api.DefaultHeaders.Add("Authorization", "Bearer " + User.GetToken());
long tenantId = long.Parse(User.TenantId);
string requestUrl = config["TaskMail:FileBaseUrl"] + config["TaskMail:SQLPrint"];
foreach (var item in mailConfig.Attachments)
{
var req = new OpenPrintReq
{
ParamJsonStr = JsonConvert.SerializeObject(new { Id = businessId }),
PrintType = ((int)FileFormat.PDF).ToString(),
TemplateId = item.TemplateId,
TenantId = tenantId
};
var reqResult = await Api.PostAsync(requestUrl, req);
if (!reqResult.Succeeded)
return DataResult.Failed($"未能获取打印API生成的文件,请求地址:{requestUrl}");
string url = config["TaskMail:FileBaseUrl"] + @"/PrintTempFile/" + reqResult.Data.Data;
var fileResult = await Api.SendRequestAsync(HttpMethod.Get, url);
if (!fileResult.Succeeded)
return DataResult.Failed($"未能获取打印API生成的文件,附件地址:{url}");
string fileName = item.FileName.IsNullOrEmpty() ? Path.GetFileName(reqResult.Data.Data) : item.FileName;
var bytes = await fileResult.Data.Content.ReadAsByteArrayAsync();
string base64Str = Convert.ToBase64String(bytes);
attachmentList.Add(new Tuple(fileName, base64Str));
}
}
dynamic[] mailParams = [new
{
SendTo = string.Join(",", receiverList.Select(x => x.Email)),
Title = title,
Body = content,
CCTo = string.Join(",", ccList),
ShowName = senderConfig.ShowName.IsNullOrEmpty() ? sender.UserName : senderConfig.ShowName,
Account = senderConfig.MailAccount,
senderConfig.Password,
Server = senderConfig.SmtpServer,
Port = senderConfig.SmtpPort.GetValueOrDefault(),
UseSSL = senderConfig.SmtpSSL.GetValueOrDefault(),
Attaches = attachmentList.Select(x => new
{
AttachName = x.Item1,
AttachContent = x.Item2
}).ToList()
}];
var mailResult = await Api.SendRequestAsync(HttpMethod.Post, config["TaskMail:MailApiUrl"], mailParams);
if (mailResult.Data.IsSuccessStatusCode)
{
return DataResult.Successed($"已发邮件(委托单:{templateModel.Primary.CustomerNo}),收件人:"
+ string.Join(",", receiverList.Select(x => x.Email)) + "发件人:" + senderConfig.MailAccount);
}
return DataResult.Failed($"邮件发送失败,API返回状态为:{(int)mailResult.Data.StatusCode} {mailResult.Data.StatusCode}"
+ "(委托单:{templateModel.Primary.CustomerNo}),收件人:"
+ string.Join(",", receiverList.Select(x => x.Email))
+ "发件人:" + senderConfig.MailAccount);
}
catch (Exception ex)
{
await ex.LogAsync(Db);
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.HttpRequestFailed));
}
}
}
}