using Furion; using Furion.DistributedIDGenerator; using Furion.DynamicApiController; using Furion.FriendlyException; using Furion.JsonSerialization; using Furion.RemoteRequest.Extensions; using HtmlAgilityPack; using Mapster; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Myshipping.Application.ConfigOption; using Myshipping.Application.Entity; using Myshipping.Application.Enum; using Myshipping.Application.Service.BookingSlot.Dto; using Myshipping.Core; using Myshipping.Core.Entity; using Myshipping.Core.Service; using Newtonsoft.Json; using Npoi.Mapper; using NPOI.HPSF; using NPOI.SS.Formula.Functions; using RabbitMQ.Client; using SqlSugar; using StackExchange.Profiling.Internal; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Security.Principal; using System.Text; using System.Threading.Tasks; using System.Web; using System.Xml; using Yitter.IdGenerator; namespace Myshipping.Application { /// /// BC任务 /// [ApiDescriptionSettings("Application", Name = "TaskManageBC", Order = 10)] public class TaskManageBCService: ITaskManageBCService, IDynamicApiController { private readonly ISysCacheService _cache; private readonly ILogger _logger; private readonly SqlSugarRepository _taskBCInfoRepository; private readonly SqlSugarRepository _taskBCCTNInfoRepository; private readonly SqlSugarRepository _taskBaseRepository; private readonly SqlSugarRepository _taskFileRepository; private readonly SqlSugarRepository _bookingOrderRepository; private readonly SqlSugarRepository _bookingCtnRepository; private readonly SqlSugarRepository _sysUserRepository; private readonly SqlSugarRepository _bookingFileRepository; private readonly SqlSugarRepository _djyUserMailAccount; private readonly SqlSugarRepository _bookingOrderContactRepository; private readonly IServiceWorkFlowBaseService _serviceWorkFlowBaseService; private readonly IBookingOrderService _bookingOrderService; private readonly IBookingSlotService _bookingSlotService; private readonly IBookingValueAddedService _bookingValueAddedService; private readonly IDjyCustomerService _djyCustomerService; const string CONST_BC_FILE_CODE = "bc"; const string CONST_BC_FILE_NAME = "Booking Confirmation"; const string CONST_BC_NOTICE_FILE_CODE = "bc_notice"; const string CONST_BC_NOTICE_FILE_NAME = "Booking Confirmation Notice"; public TaskManageBCService(SqlSugarRepository taskBCInfoRepository, SqlSugarRepository taskBaseRepository, SqlSugarRepository taskBCCTNInfoRepository, SqlSugarRepository taskFileRepository, SqlSugarRepository bookingOrderRepository, SqlSugarRepository bookingCtnRepository, SqlSugarRepository sysUserRepository, SqlSugarRepository bookingFileRepository, SqlSugarRepository djyUserMailAccount, IServiceWorkFlowBaseService serviceWorkFlowBaseService, IBookingOrderService bookingOrderService, ILogger logger, IDjyCustomerService djyCustomerService, IBookingSlotService bookingSlotService, ISysCacheService cache, IBookingValueAddedService bookingValueAddedService, SqlSugarRepository bookingOrderContactRepository) { _taskBaseRepository = taskBaseRepository; _taskBCInfoRepository = taskBCInfoRepository; _taskBCCTNInfoRepository = taskBCCTNInfoRepository; _taskFileRepository = taskFileRepository; _bookingOrderRepository = bookingOrderRepository; _bookingCtnRepository = bookingCtnRepository; _sysUserRepository = sysUserRepository; _serviceWorkFlowBaseService = serviceWorkFlowBaseService; _bookingOrderService = bookingOrderService; _bookingSlotService = bookingSlotService; _cache = cache; _bookingValueAddedService = bookingValueAddedService; _bookingFileRepository = bookingFileRepository; _djyCustomerService = djyCustomerService; _djyUserMailAccount = djyUserMailAccount; _bookingOrderContactRepository = bookingOrderContactRepository; _logger = logger; } #region 获取BC详情 /// /// 获取BC详情 /// /// BC主键 /// 返回回执 [HttpGet("/TaskManageBC/GetInfo")] public async Task GetInfo(string pkId) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); try { var bcOrder = _taskBCInfoRepository.AsQueryable().First(a => a.PK_ID == pkId); if (bcOrder == null) throw Oops.Oh($"BC主键{pkId}无法获取业务信息"); var BCCtnList = _taskBCCTNInfoRepository.AsQueryable().Where(a => a.P_ID == pkId).ToList(); TaskBCShowBaseDto model = bcOrder.Adapt(); if (BCCtnList.Count > 0) model.CtnList = BCCtnList.Adapt>(); var fileList = _taskFileRepository.AsQueryable().Where(a => a.TASK_PKID == bcOrder.TASK_ID).ToList(); if (fileList.Count > 0) model.FileList = fileList.Adapt>(); result.succ = true; result.ext = model; //如果当前BC有对应记录,则读取订舱详情 if (bcOrder.BOOKING_ORDER_ID.HasValue) { var bkOrder = await _bookingOrderRepository.AsQueryable(). FirstAsync(a => a.Id == bcOrder.BOOKING_ORDER_ID.Value); if (bkOrder != null) { var showBKOrder = bkOrder.Adapt(); var ctnList = await _bookingCtnRepository.AsQueryable(). Where(a => a.BILLID == bkOrder.Id).ToListAsync(); if (ctnList.Count > 0) showBKOrder.ctnInputs = ctnList.Adapt>(); result.ext2 = showBKOrder; } } } catch (Exception ex) { result.succ = false; result.msg = $"获取BC详情异常,原因:{ex.Message}"; } return result; } #endregion #region 通过任务主键获取BC详情 /// /// 通过任务主键获取BC详情 /// /// BC任务主键 /// 返回回执 [HttpGet("/TaskManageBC/GetInfoByTaskId")] public async Task GetInfoByTaskId(string taskPkId) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); try { var taskBase = _taskBaseRepository.AsQueryable().First(a => a.PK_ID == taskPkId); if (taskBase == null) throw Oops.Oh($"任务主键{taskPkId}无法获取业务信息"); var bcOrder = _taskBCInfoRepository.AsQueryable().First(a => a.TASK_ID == taskBase.PK_ID); if (bcOrder == null) throw Oops.Oh($"任务主键{taskPkId}无法获取BC业务信息"); var bcCtnList = _taskBCCTNInfoRepository.AsQueryable().Where(a => a.P_ID == bcOrder.PK_ID).ToList(); TaskBCShowBaseDto model = bcOrder.Adapt(); if (bcCtnList.Count > 0) model.CtnList = bcCtnList.Adapt>(); var fileList = _taskFileRepository.AsQueryable().Where(a => a.TASK_PKID == bcOrder.TASK_ID).ToList(); if (fileList.Count > 0) model.FileList = fileList.Adapt>(); model.taskStatus = taskBase.STATUS; //生成关键信息 #region 生成关键信息 model.Keywords = new List(); if(bcOrder.CARRIAGE_TYPE == "DIRECT_SHIP") { model.Keywords.Add(new TaskBCShowBaseKeywordDto() { Name = $"承运方式:{bcOrder.CARRIAGE_TYPE_NAME}", Background = "#FFFF80",Icon= "icon-yunshu1" }); } else if (bcOrder.CARRIAGE_TYPE == "TRANSFER_SHIP") { model.Keywords.Add(new TaskBCShowBaseKeywordDto() { Name = $"承运方式:{bcOrder.CARRIAGE_TYPE_NAME}", Background = "#CAF982", Icon = "icon-shuaxin" }); } if (bcOrder.BOOKING_SLOT_TYPE == "CONTRACT_ORDER") { model.Keywords.Add(new TaskBCShowBaseKeywordDto() { Name = $"订舱方式:{bcOrder.BOOKING_SLOT_TYPE_NAME}", Background = "#81D3F8", Icon = "icon-touzijilu" }); } else if (bcOrder.BOOKING_SLOT_TYPE == "SPOT_ORDER") { model.Keywords.Add(new TaskBCShowBaseKeywordDto() { Name = $"订舱方式:{bcOrder.BOOKING_SLOT_TYPE_NAME}", Background = "#FACD91", Icon = "icon-beizhu1" }); } #endregion result.succ = true; result.ext = model; //如果当前BC有对应记录,则读取订舱详情 if (bcOrder.BOOKING_ORDER_ID.HasValue) { var bkOrder = await _bookingOrderRepository.AsQueryable(). FirstAsync(a => a.Id == bcOrder.BOOKING_ORDER_ID.Value); if(bkOrder != null) { var showBKOrder = bkOrder.Adapt(); var ctnList = await _bookingCtnRepository.AsQueryable(). Where(a => a.BILLID == bkOrder.Id).ToListAsync(); if (ctnList.Count > 0) showBKOrder.ctnInputs = ctnList.Adapt>(); result.ext2 = showBKOrder; } } } catch (Exception ex) { result.succ = false; result.msg = $"获取BC详情异常,原因:{ex.Message}"; } return result; } #endregion #region 获取待处理的BC任务 /// /// 获取待处理的BC任务(来自邮件解析需要对应订舱,系统会根据用户的订舱台账预配) /// /// 返回回执 [HttpGet("/TaskManageBC/GetToDoBCList")] public async Task GetToDoBCList() { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); /* 1、优先匹配提单号一致的 2、判断船名航次一致的 */ try { Dictionary> toDoListDict = new Dictionary>(); //获取所有待处理的BC任务 var taskList = await _taskBCInfoRepository.AsQueryable().InnerJoin((a,b)=>a.TASK_ID == b.PK_ID) .Where((a, b)=> !a.BOOKING_ORDER_ID.HasValue && b.STATUS == TaskStatusEnum.Create.ToString()) .Select((a,b)=>new { BC = a,TSK = b }).ToListAsync(); if (taskList.Count > 0) { taskList.ForEach(async tsk => { var curList = await _bookingOrderRepository.AsQueryable() .Where(a => a.VESSEL.Contains(tsk.BC.VESSEL) && a.VOYNO.Contains(tsk.BC.VOYNO) || a.MBLNO.Contains(tsk.BC.MBL_NO) ).ToListAsync(); if (curList.Count > 0) { toDoListDict.Add(tsk.BC.PK_ID, curList); } else { toDoListDict.Add(tsk.BC.PK_ID, new List()); } }); } //这里最后清洗一下对应的订舱数据,只保留一条符合的数据 if (toDoListDict.Count > 0) { List> tupList = new List>(); int num = 1; int odNum = 1; foreach (var kvp in toDoListDict) { var bcInfo = taskList.FirstOrDefault(a => a.BC.PK_ID == kvp.Key).BC.Adapt(); bcInfo.Indx = num; if (kvp.Value.Count > 0) { var bookingOrder = kvp.Value.Select(a => { if (a.MBLNO.Equals(bcInfo.MBLNo, StringComparison.OrdinalIgnoreCase)) { return new { Sort = 90, OBJ = a }; } else if (a.VESSEL.Equals(bcInfo.Vessel, StringComparison.OrdinalIgnoreCase) && a.VOYNO.Equals(bcInfo.VoyNo, StringComparison.OrdinalIgnoreCase)) { return new { Sort = 80, OBJ = a }; } return new { Sort = 1, OBJ = a }; }).OrderByDescending(a => a.Sort).FirstOrDefault().OBJ.Adapt(); bookingOrder.Indx = odNum; bookingOrder.BCIndx = num; bcInfo.BKOrderIndx = odNum; odNum++; tupList.Add(new Tuple( bcInfo, bookingOrder )); } else { tupList.Add(new Tuple( bcInfo, null )); } num++; } result.ext = tupList.Select(a=>a.Item1).ToList(); result.ext2 = tupList.Select(a => a.Item2).ToList(); } result.succ = true; } catch (Exception ex) { result.succ = false; result.msg = $"获取派车详情异常,原因:{ex.Message}"; } return result; } #endregion #region 任务ID下载附件 /// /// 任务ID下载附件 /// /// BC任务主键 /// 附件分类代码 /// 返回数据流 [HttpGet("/TaskManageBC/DownloadFile")] public async Task DownloadFile([FromQuery] string taskPKId, [FromQuery] string fileCategory = "BC") { var bcTaskInfo = await _taskBaseRepository.AsQueryable().FirstAsync(u => u.PK_ID == taskPKId); if (bcTaskInfo == null) { throw Oops.Oh($"任务主键{taskPKId}无法获取业务信息"); } TaskFileCategoryEnum fileCategoryEnum = TaskFileCategoryEnum.NONE; System.Enum.TryParse(fileCategory, out fileCategoryEnum); if (fileCategoryEnum == TaskFileCategoryEnum.NONE) { throw Oops.Oh($"附件分类代码错误,请提供正确的分类代码"); } string name = fileCategoryEnum.ToString(); var fileInfo = await _taskFileRepository.AsQueryable().FirstAsync(u => u.TASK_PKID == taskPKId && u.FILE_CATEGORY == name); if (fileInfo == null) { throw Oops.Oh($"任务主键{taskPKId}没有可下载的附件"); } var opt = App.GetOptions(); var dirAbs = opt.basePath; if (string.IsNullOrEmpty(dirAbs)) { dirAbs = App.WebHostEnvironment.WebRootPath; } var fileFullPath = Path.Combine(dirAbs, fileInfo.FILE_PATH); if (!File.Exists(fileFullPath)) { throw Oops.Oh($"任务主键{taskPKId} 附件下载请求失败,请确认文件是否存在"); } var fileName = HttpUtility.UrlEncode(fileInfo.FILE_NAME, Encoding.GetEncoding("UTF-8")); var result = new FileStreamResult(new FileStream(fileFullPath, FileMode.Open), "application/octet-stream") { FileDownloadName = fileName }; return result; } #endregion #region 检索订舱信息 /// /// 检索订舱信息 /// /// 检索条件 /// 返回回执 [HttpPost("/TaskManageBC/QueryBookingOrderList")] public async Task QueryBookingOrderList([FromBody] BookingOrderBCQuery query) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); try { bool isAvailable = false; var queryWhere = _bookingOrderRepository.AsQueryable(); #region 查询条件 if (query.beginETD.HasValue || query.endETD.HasValue) { /* 起始结束时间间隔不能超过7天 */ DateTime beginDate = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd")); DateTime endDate = beginDate; if (query.beginETD.HasValue) beginDate = query.beginETD.Value; if (query.endETD.HasValue) endDate = query.endETD.Value; if (endDate > beginDate.AddDays(7)) throw Oops.Oh($"船期的日期范围不能超过7天"); endDate = endDate.AddDays(1); queryWhere = queryWhere.Where(a => a.ETD >= beginDate && a.ETD < endDate); isAvailable = true; } if (query.beginCreated.HasValue || query.endCreated.HasValue) { /* 起始结束时间间隔不能超过7天 */ DateTime beginDate = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd")); DateTime endDate = beginDate; if (query.beginCreated.HasValue) beginDate = query.beginCreated.Value; if (query.endCreated.HasValue) endDate = query.endCreated.Value; if (endDate > beginDate.AddDays(7)) throw Oops.Oh($"制单的日期范围不能超过7天"); endDate = endDate.AddDays(1); queryWhere = queryWhere.Where(a => a.CreatedTime >= beginDate && a.CreatedTime < endDate); isAvailable = true; } if (!string.IsNullOrWhiteSpace(query.mblNo)) { queryWhere = queryWhere.Where(a => a.MBLNO.Contains(query.mblNo)); isAvailable = true; } if (!string.IsNullOrWhiteSpace(query.custNo)) { queryWhere = queryWhere.Where(a => a.CUSTNO.Contains(query.custNo)); isAvailable = true; } if (!string.IsNullOrWhiteSpace(query.vessel)) { queryWhere = queryWhere.Where(a => a.VESSEL.Contains(query.vessel)); isAvailable = true; } if (!string.IsNullOrWhiteSpace(query.voyno)) { queryWhere = queryWhere.Where(a => a.VOYNO.Contains(query.voyno)); isAvailable = true; } #endregion if (!isAvailable) throw Oops.Oh($"查询条件不能为空"); var list = await queryWhere.OrderBy(a => a.CreatedTime) .Take(query.topNum).ToListAsync(); var bkList = list.Adapt>(); result.succ = true; result.ext = bkList; } catch (Exception ex) { result.succ = false; result.msg = $"查询失败,原因:{ex.Message}"; } return result; } #endregion #region 转移任务(将任务指定给其他人) /// /// 转移任务(将任务指定给其他人) /// /// BC任务主键 /// 用户ID /// 返回回执 [HttpGet("/TaskManageBC/TransferTask")] public async Task TransferTask([FromQuery] string taskPKId, [FromQuery] long userId) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); try { /* 1、如果当前任务是公共任务,则更新为相关人后,变更任务为个人。 */ var bcTaskInfo = await _taskBaseRepository.AsQueryable().FirstAsync(u => u.PK_ID == taskPKId); if (bcTaskInfo == null) { throw Oops.Oh($"任务主键{taskPKId}无法获取业务信息"); } if(userId < 0) throw Oops.Oh($"指定用户ID不能为空"); var targetUserId = _sysUserRepository.AsQueryable().First(u => u.Id == userId); if (targetUserId == null) throw Oops.Oh($"指定用户不存在"); if (bcTaskInfo.IS_PUBLIC == 1) { bcTaskInfo.IS_PUBLIC = 0; bcTaskInfo.CreatedUserId = targetUserId.Id; bcTaskInfo.CreatedUserName = targetUserId.Name; bcTaskInfo.UpdatedTime = DateTime.Now; bcTaskInfo.UpdatedUserId = targetUserId.Id; bcTaskInfo.UpdatedUserName = targetUserId.Name; await _taskBaseRepository.AsUpdateable(bcTaskInfo).IgnoreColumns(it => new { it.TenantId, it.CreatedTime, it.IsDeleted, it.TASK_NO, it.TASK_TYPE, it.TASK_SOURCE }).ExecuteCommandAsync(); } else { bcTaskInfo.CreatedUserId = targetUserId.Id; bcTaskInfo.CreatedUserName = targetUserId.Name; bcTaskInfo.UpdatedTime = DateTime.Now; bcTaskInfo.UpdatedUserId = targetUserId.Id; bcTaskInfo.UpdatedUserName = targetUserId.Name; await _taskBaseRepository.AsUpdateable(bcTaskInfo).IgnoreColumns(it => new { it.TenantId, it.CreatedTime, it.IsDeleted, it.TASK_NO, it.TASK_TYPE, it.TASK_SOURCE }).ExecuteCommandAsync(); } result.succ = true; result.msg = "成功"; } catch (Exception ex) { result.succ = false; result.msg = $"转移任务失败,原因:{ex.Message}"; } return result; } #endregion #region 生成订舱或舱位 /// /// 生成订舱或舱位 /// /// 生成订舱或者舱位请求 /// 返回回执 [HttpPost("/TaskManageBC/CreateBookingAndSlot")] public async Task CreateBookingAndSlot([FromBody] BookingOrSlotGenerateDto model) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); try { /* 1、GEN_BOOKING_SLOT-生成舱位和订舱 (1)生成舱位 (2)生成海运订舱 (3)更新舱位库存 (4)更新BC任务 2、GEN_BOOKING-只生成订舱 (1)生成海运订舱 (4)更新BC任务 3、GEN_SLOT-只生成舱位 (1)生成舱位 (4)更新BC任务 3、GEN_SLOT-只生成舱位 (1)查找订舱记录 (3)更新舱位库存 (4)更新BC任务 */ if (string.IsNullOrWhiteSpace(model.BCTaskId)) throw Oops.Oh($"BC任务主键不能为空"); //生成方式(GEN_BOOKING_SLOT-生成舱位和订舱;GEN_BOOKING-只生成订舱;GEN_SLOT-只生成舱位;GEN_EXIST_BOOKING-匹配指定的订舱) if (string.IsNullOrWhiteSpace(model.GenerateMethod)) throw Oops.Oh($"生成方式不能为空,需要指定一种生成方式"); var bcTaskInfo = await _taskBaseRepository.AsQueryable().FirstAsync(u => u.PK_ID == model.BCTaskId); if (bcTaskInfo == null) { throw Oops.Oh($"任务主键{model.BCTaskId}无法获取业务信息"); } var bcOrder = _taskBCInfoRepository.AsQueryable().First(a => a.TASK_ID == bcTaskInfo.PK_ID); if (bcOrder == null) throw Oops.Oh($"任务主键{model.BCTaskId}无法获取BC业务信息"); var bcCtnList = _taskBCCTNInfoRepository.AsQueryable().Where(a => a.P_ID == bcOrder.PK_ID).ToList(); var fileList = _taskFileRepository.AsQueryable().Where(a => a.TASK_PKID == bcTaskInfo.PK_ID).ToList(); if (bcOrder.BOOKING_ORDER_ID.HasValue && bcOrder.BOOKING_ORDER_ID.Value > 0) { throw Oops.Oh($"当前BC任务已生成订舱或舱位,不能重复生成"); } if (model.GenerateMethod == "GEN_BOOKING_SLOT") { #region 推送舱位、推送订舱 //推送舱位 long bookingSlotId = 0; if(bcOrder.BOOKING_SLOT_ID.HasValue && bcOrder.BOOKING_SLOT_ID.Value > 0) { bookingSlotId = bcOrder.BOOKING_SLOT_ID.Value; } else { bookingSlotId = await GenerateBookingSlot(bcOrder, bcCtnList, fileList); } if (bookingSlotId > 0) { //推送订舱 var bookingOrderId = await GenerateBookingOrder(bcOrder, bcCtnList, fileList, model); if (bookingOrderId > 0) { //更新库存 //_bookingSlotService. var bcEntity = _taskBCInfoRepository.AsQueryable().First(a => a.PK_ID == bcOrder.PK_ID); if (bcEntity != null) { if (bookingOrderId > 0) bcEntity.BOOKING_ORDER_ID = bookingOrderId; if (bookingSlotId > 0) bcEntity.BOOKING_SLOT_ID = bookingSlotId; bcEntity.UpdatedTime = DateTime.Now; bcEntity.UpdatedUserId = UserManager.UserId; bcEntity.UpdatedUserName = UserManager.Name; _taskBCInfoRepository.AsUpdateable(bcEntity).UpdateColumns(it => new { it.BOOKING_ORDER_ID, it.BOOKING_SLOT_ID, it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName }).ExecuteCommand(); var currBCOrder = _taskBCInfoRepository.AsQueryable().First(a => a.PK_ID == bcEntity.PK_ID); if (currBCOrder != null) await GenerateSendEmail(currBCOrder); var taskEntity = _taskBaseRepository.AsQueryable().First(u => u.PK_ID == bcEntity.TASK_ID); if (taskEntity != null && taskEntity.IS_PUBLIC == 1) { taskEntity.IS_PUBLIC = 0; taskEntity.CreatedUserId = UserManager.UserId; taskEntity.CreatedUserName = UserManager.Name; taskEntity.UpdatedTime = DateTime.Now; taskEntity.UpdatedUserId = UserManager.UserId; taskEntity.UpdatedUserName = UserManager.Name; _taskBaseRepository.AsUpdateable(taskEntity).UpdateColumns(it => new { it.IS_PUBLIC, it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName, it.CreatedUserId, it.CreatedUserName }).ExecuteCommand(); } } } } else { throw Oops.Oh($"生成舱位失败,舱位已存在"); } #endregion } else if (model.GenerateMethod == "GEN_BOOKING") { #region 推送订舱 //推送订舱 var bookingOrderId = GenerateBookingOrder(bcOrder, bcCtnList, fileList, model).GetAwaiter().GetResult(); if (bookingOrderId > 0) { //异步推送邮件 await GenerateSendEmail(bcOrder); var bcEntity = _taskBCInfoRepository.AsQueryable().First(a => a.PK_ID == bcTaskInfo.PK_ID); if (bcEntity != null) { if (bookingOrderId > 0) bcEntity.BOOKING_ORDER_ID = bookingOrderId; bcEntity.UpdatedTime = DateTime.Now; bcEntity.UpdatedUserId = UserManager.UserId; bcEntity.UpdatedUserName = UserManager.Name; _taskBCInfoRepository.AsUpdateable(bcEntity).UpdateColumns(it => new { it.BOOKING_ORDER_ID, it.BOOKING_SLOT_ID, it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName }).ExecuteCommand(); var taskEntity = _taskBaseRepository.AsQueryable().First(u => u.PK_ID == bcEntity.TASK_ID); if (taskEntity != null && taskEntity.IS_PUBLIC == 1) { taskEntity.IS_PUBLIC = 0; taskEntity.CreatedUserId = UserManager.UserId; taskEntity.CreatedUserName = UserManager.Name; taskEntity.UpdatedTime = DateTime.Now; taskEntity.UpdatedUserId = UserManager.UserId; taskEntity.UpdatedUserName = UserManager.Name; _taskBaseRepository.AsUpdateable(taskEntity).UpdateColumns(it => new { it.IS_PUBLIC, it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName, it.CreatedUserId, it.CreatedUserName }).ExecuteCommand(); } } } #endregion } else if (model.GenerateMethod == "GEN_BOOKING_SLOT") { #region 推送舱位 //推送舱位 var bookingSlotId = GenerateBookingSlot(bcOrder, bcCtnList, fileList).GetAwaiter().GetResult(); if (bookingSlotId > 0) { var bcEntity = _taskBCInfoRepository.AsQueryable().First(a => a.PK_ID == bcTaskInfo.PK_ID); if (bcEntity != null) { if (bookingSlotId > 0) bcEntity.BOOKING_SLOT_ID = bookingSlotId; bcEntity.UpdatedTime = DateTime.Now; bcEntity.UpdatedUserId = UserManager.UserId; bcEntity.UpdatedUserName = UserManager.Name; _taskBCInfoRepository.AsUpdateable(bcEntity).UpdateColumns(it => new { it.BOOKING_ORDER_ID, it.BOOKING_SLOT_ID, it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName }).ExecuteCommand(); var taskEntity = _taskBaseRepository.AsQueryable().First(u => u.PK_ID == bcEntity.TASK_ID); if (taskEntity != null && taskEntity.IS_PUBLIC == 1) { taskEntity.IS_PUBLIC = 0; taskEntity.CreatedUserId = UserManager.UserId; taskEntity.CreatedUserName = UserManager.Name; taskEntity.UpdatedTime = DateTime.Now; taskEntity.UpdatedUserId = UserManager.UserId; taskEntity.UpdatedUserName = UserManager.Name; _taskBaseRepository.AsUpdateable(taskEntity).UpdateColumns(it => new { it.IS_PUBLIC, it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName, it.CreatedUserId, it.CreatedUserName }).ExecuteCommand(); } } } #endregion } result.succ = true; result.msg = "成功"; } catch (Exception ex) { result.succ = false; result.msg = $"生成订舱或舱位失败,原因:{ex.Message}"; } return result; } #endregion #region 生成舱位 /// /// 生成舱位 /// /// BC任务详情 /// BC任务集装箱列表 /// BC任务附件列表 /// 返回舱位ID private async Task GenerateBookingSlot(TaskBCInfo taskBCInfo, List taskBCCtnList, List taskFileList) { long id = 0; try { var carrierInfo = _cache.GetAllCodeCarrier().GetAwaiter().GetResult() .Where(t => t.Code.Equals(taskBCInfo.CARRIERID, StringComparison.OrdinalIgnoreCase) || t.EnName.Equals(taskBCInfo.CARRIERID, StringComparison.OrdinalIgnoreCase) || t.CnName.Equals(taskBCInfo.CARRIERID, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); BookingSlotBaseApiDto slotModel = new BookingSlotBaseApiDto { DataObj = new BookingSlotBaseApiSaveDto { CARRIERID = taskBCInfo.CARRIERID, CARRIER = carrierInfo.CnName?.Trim(), SLOT_BOOKING_NO = taskBCInfo.MBL_NO, BOOKING_PARTY = taskBCInfo.BOOKING_PARTY, BOOKING_SLOT_TYPE = taskBCInfo.BOOKING_SLOT_TYPE, BOOKING_SLOT_TYPE_NAME = taskBCInfo.BOOKING_SLOT_TYPE_NAME, VESSEL = taskBCInfo.VESSEL, VOYNO = taskBCInfo.VOYNO, VGM_SUBMISSION_CUT_DATE = taskBCInfo.VGM_CUTOFF_TIME, WEEK_AT = taskBCInfo.WEEK_AT, CARRIAGE_TYPE = taskBCInfo.CARRIAGE_TYPE, CARRIAGE_TYPE_NAME = taskBCInfo.CARRIAGE_TYPE_NAME, CONTRACT_NO = taskBCInfo.CONTRACTNO, CTN_STAT = taskBCInfo.CTN_STAT, CY_CUT_DATE = taskBCInfo.CY_CUTOFF_TIME, DETENSION_FREE_DAYS = taskBCInfo.DETENSION_FREE_DAYS, ETD = taskBCInfo.ETD, ETA = taskBCInfo.ETA, LANECODE = taskBCInfo.LANECODE, LANENAME = taskBCInfo.LANENAME, MANIFEST_CUT_DATE = taskBCInfo.MANIFEST_CUT_DATE, MDGF_CUT_DATE = taskBCInfo.MDGF_CUT_DATE, PLACEDELIVERY = taskBCInfo.PLACEDELIVERY, PLACERECEIPT = taskBCInfo.PLACERECEIPT, PORTDISCHARGE = taskBCInfo.PORTDISCHARGE, PORTLOAD = taskBCInfo.PORTLOAD, SI_CUT_DATE = taskBCInfo.SI_CUT_DATE, TRANSFER_PORT_1 = taskBCInfo.TRANSFER_PORT_1, TRANSFER_PORT_2 = taskBCInfo.TRANSFER_PORT_2, CtnList = new List() }, OpType = "add" }; var ctnCodeList = _cache.GetAllCodeCtn().GetAwaiter().GetResult().ToList(); if (taskBCCtnList.Count > 0) { taskBCCtnList.ForEach(t => { var ctnCode = ctnCodeList.FirstOrDefault(a => !string.IsNullOrWhiteSpace(a.Name) && a.Name.Equals(t.CTNALL, StringComparison.OrdinalIgnoreCase)); BookingSlotCtnSaveInput ctn = new BookingSlotCtnSaveInput { CTNCODE = ctnCode?.Code, CTNALL = t.CTNALL, CTNNUM = t.CTNNUM.HasValue ? t.CTNNUM.Value : 1 }; slotModel.DataObj.CtnList.Add(ctn); }); } var opt = App.GetOptions(); var dirAbs = opt.basePath; if (string.IsNullOrEmpty(dirAbs)) { dirAbs = App.WebHostEnvironment.WebRootPath; } DynameFileInfo dynameFile = null; DynameFileInfo dynameNoticeFile = null; if (taskFileList.Any(t => t.FILE_CATEGORY == TaskFileCategoryEnum.BC.ToString())) { var fileInfo = taskFileList.FirstOrDefault(t => t.FILE_CATEGORY == TaskFileCategoryEnum.BC.ToString()); var fileFullPath = Path.Combine(dirAbs, fileInfo.FILE_PATH); dynameFile = new DynameFileInfo { FileBytes = File.ReadAllBytes(fileFullPath), FileName = Path.GetFileName(fileFullPath) }; } if (taskFileList.Any(t => t.FILE_CATEGORY == TaskFileCategoryEnum.BC_NOTICE.ToString())) { var fileInfo = taskFileList.FirstOrDefault(t => t.FILE_CATEGORY == TaskFileCategoryEnum.BC.ToString()); var fileFullPath = Path.Combine(dirAbs, fileInfo.FILE_PATH); dynameNoticeFile = new DynameFileInfo { FileBytes = File.ReadAllBytes(fileFullPath), FileName = Path.GetFileName(fileFullPath) }; } id = await _bookingSlotService.InnerApiReceive(slotModel, dynameFile, dynameNoticeFile); } catch (Exception ex) { _logger.LogError($"任务BC MBLNO:{taskBCInfo.MBL_NO} 生成舱位异常,原因:{ex.Message}"); } return id; } #endregion #region 生成订舱 /// /// 生成订舱 /// /// BC任务详情 /// BC任务集装箱列表 /// BC任务附件列表 /// 订舱请求详情 /// 返回订舱ID private async Task GenerateBookingOrder(TaskBCInfo taskBCInfo, List taskBCCtnList, List taskFileList, BookingOrSlotGenerateDto generateModel) { long id = 0; try { /* 1、新增订舱 2、推送服务项目 3、推送附件 */ var carrierInfo = _cache.GetAllCodeCarrier().GetAwaiter().GetResult() .Where(t => t.Code.Equals(taskBCInfo.CARRIERID, StringComparison.OrdinalIgnoreCase) || t.EnName.Equals(taskBCInfo.CARRIERID, StringComparison.OrdinalIgnoreCase) || t.CnName.Equals(taskBCInfo.CARRIERID, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); SaveBookingOrderInput bkModel = new SaveBookingOrderInput { CUSTOMERID = generateModel.CustomerId, CUSTOMERNAME = generateModel.CustomerName, CARRIERID = carrierInfo.Code?.Trim(), CARRIER = carrierInfo.CnName?.Trim(), MBLNO = taskBCInfo.MBL_NO.ToUpper().Trim(), CONTRACTNO = !string.IsNullOrWhiteSpace(taskBCInfo.CONTRACTNO) ? taskBCInfo.CONTRACTNO : "", VESSEL = taskBCInfo.VESSEL.ToUpper().Trim(), VOYNO = taskBCInfo.VOYNO.ToUpper().Trim(), VOYNOINNER = taskBCInfo.VOYNO.ToUpper().Trim(), ETD = taskBCInfo.ETD, ETA = taskBCInfo.ETA, SALEID = generateModel.SaleId.ToString(), SALE = generateModel.SaleName, OPID = generateModel.OpId.ToString(), OP = generateModel.OpName, DOCID = generateModel.DocId.ToString(), DOC = generateModel.DocName, ROUTEID = generateModel.RouteID.ToString(), ROUTE = generateModel.Route, CZRemark = generateModel.CZRemark, ShenQingXiangShi = generateModel.ShenQingXiangShi, LineManageID = generateModel.LineManageID.ToString(), LineName = generateModel.LineManage, CLOSEVGMDATE = taskBCInfo.VGM_CUTOFF_TIME, CLOSINGDATE = taskBCInfo.CY_CUTOFF_TIME, CLOSEDOCDATE = taskBCInfo.CUT_SINGLE_TIME, ctnInputs = new List() }; var ctnCodeList = _cache.GetAllCodeCtn().GetAwaiter().GetResult().ToList(); if (taskBCCtnList.Count > 0) { taskBCCtnList.ForEach(t => { var ctnCode = ctnCodeList.FirstOrDefault(a => !string.IsNullOrWhiteSpace(a.Name) && a.Name.Equals(t.CTNALL, StringComparison.OrdinalIgnoreCase)); BookingCtnDto ctn = new BookingCtnDto { CTNCODE = ctnCode?.Code, CTNALL = t.CTNALL, CTNNUM = t.CTNNUM.HasValue ? t.CTNNUM.Value : 1 }; bkModel.ctnInputs.Add(ctn); }); } var bkRlt = await _bookingOrderService.Save(bkModel); id = bkRlt.Id; string batchNo = IDGen.NextID().ToString(); if (id > 0) { //这里如果指定了委托单位的邮件联系人,则推送订舱联系人 if (generateModel.CustomerContactId.HasValue && generateModel.CustomerContactId.Value > 0) { var bookingContact = _bookingOrderContactRepository.AsQueryable() .Where(a => a.BookingId == id && !a.IsDeleted).First(); var djyCustomerInfo = _djyCustomerService.Detail(new GetDjyCustomerInput { Id = generateModel.CustomerId.Value }) .GetAwaiter().GetResult(); DjyCustomerContactOutput djyCustomerContactMan = null; if (djyCustomerInfo.Contacts != null && djyCustomerInfo.Contacts.Count > 0) { djyCustomerContactMan = djyCustomerInfo.Contacts.FirstOrDefault(a => a.Remark.Equals("BCNotice", StringComparison.OrdinalIgnoreCase)); } if (bookingContact == null) { bookingContact = new BookingOrderContact { Name = generateModel.CustomerContactName, BookingId = id, Email = djyCustomerContactMan.Email, Remark = djyCustomerContactMan.Remark, CreatedTime = DateTime.Now, CreatedUserId = UserManager.UserId, CreatedUserName = UserManager.Name }; await _bookingOrderContactRepository.InsertAsync(bookingContact); } else { bookingContact.Name = generateModel.CustomerContactName; bookingContact.Email = djyCustomerContactMan.Email; bookingContact.Remark = djyCustomerContactMan.Remark; bookingContact.UpdatedTime = DateTime.Now; bookingContact.UpdatedUserId = UserManager.UserId; bookingContact.UpdatedUserName = UserManager.Name; _bookingOrderContactRepository.AsUpdateable(bookingContact).UpdateColumns(it => new { it.Name, it.Email, it.Remark, it.UpdatedTime, it.UpdatedUserId, it.UpdatedUserName }).ExecuteCommand(); } } if (generateModel.ProjectList != null && generateModel.ProjectList.Count > 0) { ModifyServiceProjectDto projectDto = new ModifyServiceProjectDto { BookingId = id, ProjectCodes = generateModel.ProjectList.Distinct().ToArray(), }; //写入服务项目 var prjRlt = await _bookingValueAddedService.SaveServiceProject(projectDto); _logger.LogInformation($"推送订舱的服务项目完成 id={id} rlt={JSON.Serialize(prjRlt)}"); } var opt = App.GetOptions(); var dirAbs = opt.basePath; if (string.IsNullOrEmpty(dirAbs)) { dirAbs = App.WebHostEnvironment.WebRootPath; } taskFileList.ForEach(file => { if (file.FILE_CATEGORY == TaskFileCategoryEnum.BC.ToString()) { var fileFullPath = Path.Combine(dirAbs, file.FILE_PATH); if (File.Exists(fileFullPath)) { //如果确认文件读取成功 var bookFilePath = FileAttachHelper.MoveFile(id.ToString(), fileFullPath, batchNo).GetAwaiter().GetResult(); //将格式单附件写入订舱的附件 SaveEDIFile(id, bookFilePath, new System.IO.FileInfo(bookFilePath).Name, taskBCInfo.TenantId.Value, CONST_BC_FILE_CODE, CONST_BC_FILE_NAME).GetAwaiter(); } } else if (file.FILE_CATEGORY == TaskFileCategoryEnum.BC_NOTICE.ToString()) { var fileFullPath = Path.Combine(dirAbs, file.FILE_PATH); if (File.Exists(fileFullPath)) { //如果确认文件读取成功 var bookFilePath = FileAttachHelper.MoveFile(id.ToString(), fileFullPath, batchNo, false, "bcnoticefile").GetAwaiter().GetResult(); //将格式单附件写入订舱的附件 SaveEDIFile(id, bookFilePath, new System.IO.FileInfo(bookFilePath).Name, taskBCInfo.TenantId.Value, CONST_BC_NOTICE_FILE_CODE, CONST_BC_NOTICE_FILE_NAME).GetAwaiter(); } } }); } _logger.LogInformation($"任务BC MBLNO:{taskBCInfo.MBL_NO} 生成订舱成功 id={id}"); } catch(Exception ex) { _logger.LogError($"任务BC MBLNO:{taskBCInfo.MBL_NO} 生成订舱异常,原因:{ex.Message}"); } return id; } #endregion #region 取消任务 /// /// 取消任务 /// /// BC任务主键 /// 返回回执 [HttpGet("/TaskManageBC/CancelTask")] public async Task CancelTask([FromQuery] string taskPKId) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); try { var bcTaskInfo = await _taskBaseRepository.AsQueryable().FirstAsync(u => u.PK_ID == taskPKId); if (bcTaskInfo == null) { throw Oops.Oh($"任务主键{taskPKId}无法获取业务信息"); } bcTaskInfo.IsDeleted = true; bcTaskInfo.UpdatedTime = DateTime.Now; bcTaskInfo.UpdatedUserId = UserManager.UserId; bcTaskInfo.UpdatedUserName = UserManager.Name; await _taskBaseRepository.AsUpdateable(bcTaskInfo).IgnoreColumns(it => new { it.TenantId, it.CreatedTime, it.CreatedUserId, it.CreatedUserName, it.IsDeleted, it.TASK_NO, it.TASK_TYPE, it.TASK_SOURCE }).ExecuteCommandAsync(); result.succ = true; result.msg = "成功"; } catch (Exception ex) { result.succ = false; result.msg = $"取消任务失败,原因:{ex.Message}"; } return result; } #endregion #region 获取服务项目列表 /// /// 获取服务项目列表 /// /// 返回回执 [HttpGet("/TaskManageBC/GetProjectList")] public async Task> GetProjectList() { List list = new List(); return await _serviceWorkFlowBaseService.GetEnableProjectList(UserManager.TENANT_ID.ToString()); } #endregion #region 异步写入附件表 /// /// 异步写入附件表 /// /// 订舱ID /// 文件路径 /// 文件名 /// 租户ID /// 附件类型代码 /// 附件类型名称 /// 附件模块代码 /// [NonAction] private async Task SaveEDIFile(long boookId, string FilePath, string fileName, long tenantId, string fileTypeCode = "bc", string fileTypeName = "Booking Confirmation",string moudle = "BookingSlot") { /* 直接将附件信息写入附件表 */ //EDI文件 var bookFile = new BookingFile { Id = YitIdHelper.NextId(), FileName = fileName, FilePath = FilePath, TypeCode = fileTypeCode, TypeName = fileTypeName, BookingId = boookId, TenantId = tenantId, Moudle = moudle }; await _bookingFileRepository.InsertAsync(bookFile); } #endregion #region 生成并推送邮件 /// /// 生成并推送邮件 /// /// BC任务详情 /// 返回回执 private async Task GenerateSendEmail(TaskBCInfo taskBCInfo) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); try { /* 1、提取邮件接收人、通过订舱的委托客户获取联系人信息(提取联系人中备注是BCNotice的邮箱) 2、提取当票订舱对应的操作人邮箱、通过订舱的委托客户获取操作OP的邮箱 3、读取用户邮箱配置,主要提取显示名称BCNotice的邮箱,用来作为公共邮箱来发送邮件。 4、读取邮件模板,填充详情。 5、推送邮件给邮件接收人 */ //读取订舱数据 var bookingOrderEntity = _bookingOrderRepository.AsQueryable() .First(a => a.Id == taskBCInfo.BOOKING_ORDER_ID); if (bookingOrderEntity == null) { throw Oops.Oh($"订舱详情获取失败,请确认订舱是否存在或已删除"); } _logger.LogInformation($"获取订舱详情完成,bookid={bookingOrderEntity.Id}"); if (!bookingOrderEntity.CUSTOMERID.HasValue || (bookingOrderEntity.CUSTOMERID.HasValue && bookingOrderEntity.CUSTOMERID.Value == 0)) { throw Oops.Oh($"订舱的委托客户不能为空"); } var djyCustomerInfo = _djyCustomerService.Detail(new GetDjyCustomerInput { Id = bookingOrderEntity.CUSTOMERID.Value }) .GetAwaiter().GetResult(); if (djyCustomerInfo == null) { throw Oops.Oh($"委托单位详情获取失败,请确认委托单位是否存在或已删除"); } _logger.LogInformation($"获取委托单位详情完成,djyCustomerId={djyCustomerInfo.Id}"); //DjyCustomerContactOutput djyCustomerContactMan = null; //TO 邮件接收人 string toEmail = string.Empty; //订舱OP的邮箱 string opEmail = string.Empty; var bookingContact = _bookingOrderContactRepository.AsQueryable() .First(a => a.BookingId == taskBCInfo.BOOKING_ORDER_ID); if (bookingContact == null && string.IsNullOrWhiteSpace(bookingContact.Email)) { _logger.LogInformation($"当前订舱未指定的联系人,toEmail={toEmail}"); } toEmail = bookingContact.Email.Trim(); //获取操作OP的邮箱 if (!string.IsNullOrWhiteSpace(bookingOrderEntity.OPID)) { var opId = long.Parse(bookingOrderEntity.OPID); var opUser = _sysUserRepository.AsQueryable().First(a => a.Id == opId); if (opUser != null && !string.IsNullOrWhiteSpace(opUser.Email)) { opEmail = opUser.Email.Trim(); _logger.LogInformation($"获取操作OP的邮箱,opEmail={opEmail} id={opId} name={opUser.Name}"); } } //提取当前公共邮箱的配置 var publicMailAccount = _djyUserMailAccount.FirstOrDefault(x => x.ShowName.Contains("BCNotice") && x.SmtpPort > 0 && x.SmtpServer != null && x.SmtpServer != ""); if (publicMailAccount == null) { throw Oops.Oh($"提取公共邮箱配置失败,请在用户邮箱账号管理增加配置显示名为BCNotice"); } _logger.LogInformation($"提取当前公共邮箱的配置完成,id={publicMailAccount.Id}"); string emailTitle = $"Booking Confirmation : {taskBCInfo.MBL_NO}"; string filePath = string.Empty; //读取邮件模板并填充数据 string emailHtml = GenerateSendEmailHtml(taskBCInfo, UserManager.TENANT_NAME).GetAwaiter().GetResult(); _logger.LogInformation($"生成邮件BODY,结果:{emailHtml}"); var fileInfo = _bookingFileRepository.AsQueryable().Where(a => a.BookingId == bookingOrderEntity.Id && a.TypeCode.Contains("bc_notice")) .OrderByDescending(a => a.CreatedTime).First(); if (fileInfo == null) { throw Oops.Oh($"提取订舱的Booking Confirmation Notice文件失败,不能发送邮件"); } _logger.LogInformation($"获取订舱附件地址,结果:{fileInfo.FilePath}"); var opt = App.GetOptions(); var dirAbs = opt.basePath; if (string.IsNullOrEmpty(dirAbs)) { dirAbs = App.WebHostEnvironment.WebRootPath; } filePath = Path.Combine(dirAbs, fileInfo.FilePath); EmailApiUserDefinedDto emailApiUserDefinedDto = new EmailApiUserDefinedDto { SendTo = toEmail, CCTo = opEmail, Title = emailTitle, Body = emailHtml, Account = publicMailAccount.MailAccount?.Trim(), Password = publicMailAccount.Password?.Trim(), Server = publicMailAccount.SmtpServer?.Trim(), Port = publicMailAccount.SmtpPort.HasValue ? publicMailAccount.SmtpPort.Value : 465, UseSSL = publicMailAccount.SmtpSSL.HasValue ? publicMailAccount.SmtpSSL.Value : true, Attaches = new List() }; _logger.LogInformation($"生成请求邮件参数,结果:{JSON.Serialize(emailApiUserDefinedDto)}"); //推送邮件 var emailRlt = await PushEmail(emailApiUserDefinedDto, filePath); _logger.LogInformation($"推送邮件完成,结果:{JSON.Serialize(emailRlt)}"); result.succ = true; result.msg = "成功"; } catch (Exception ex) { _logger.LogInformation($"推送邮件失败,异常:{ex.Message}"); result.succ = false; result.msg = $"推送邮件失败,异常:{ex.Message}"; } return result; } #endregion #region 通过邮件模板生成HTML /// /// 通过邮件模板生成HTML /// /// BC任务详情 /// 当前租户全称 /// 返回生成的HTML public async Task GenerateSendEmailHtml(TaskBCInfo taskBCInfo,string tenantName) { string result = string.Empty; /* 1、加载模板文件,读取HTML 2、读取main、conta的tr行,替换业务数据 3、返回HTML的文本信息。 */ try { string templatePath = App.Configuration["EmailTemplateFilePath"]; var opt = App.GetOptions(); var dirAbs = opt.basePath; if (string.IsNullOrEmpty(dirAbs)) { dirAbs = App.WebHostEnvironment.WebRootPath; } templatePath = $"{dirAbs}{templatePath}\\BCEmailTemplate.html"; string baseHtml = File.ReadAllText(templatePath); if (string.IsNullOrWhiteSpace(baseHtml)) throw Oops.Oh($"读取邮件模板失败"); HtmlDocument html = new HtmlDocument(); html.LoadHtml(baseHtml); HtmlNode baseTable = html.DocumentNode.SelectNodes("//table[@class='base-table']").FirstOrDefault(); if (baseTable == null) throw Oops.Oh($"读取邮件模板格式错误,定位base-table失败"); var baseTrList = baseTable.SelectNodes(".//tr"); foreach (var baseTr in baseTrList) { var tdList = baseTr.SelectNodes(".//td"); foreach (var baseTd in tdList) { if (baseTd.Attributes["class"].Value == "billno-val") { baseTd.InnerHtml = taskBCInfo.MBL_NO; } else if (baseTd.Attributes["class"].Value == "takebillno-val") { baseTd.InnerHtml = taskBCInfo.MBL_NO; } else if (baseTd.Attributes["class"].Value == "pol-val") { baseTd.InnerHtml = taskBCInfo.PLACERECEIPT; } else if (baseTd.Attributes["class"].Value == "pod-val") { baseTd.InnerHtml = taskBCInfo.PLACEDELIVERY; } else if (baseTd.Attributes["class"].Value == "ctn-val") { baseTd.InnerHtml = taskBCInfo.CTN_STAT; } else if (baseTd.Attributes["class"].Value == "etd-val") { if (taskBCInfo.ETD.HasValue) { baseTd.InnerHtml = taskBCInfo.ETD.Value.ToString("yyyy-MM-dd"); } } else if (baseTd.Attributes["class"].Value == "eta-val") { if (taskBCInfo.ETA.HasValue) { baseTd.InnerHtml = taskBCInfo.ETA.Value.ToString("yyyy-MM-dd"); } } } } var noreplyTr = html.DocumentNode.SelectNodes("//tr[@class='email-noreply']").FirstOrDefault(); if (noreplyTr != null) { var currTd = noreplyTr.SelectNodes(".//td").FirstOrDefault(); if(currTd != null) { var currPList = currTd.SelectNodes(".//p"); foreach (var baseP in currPList) { if (baseP.Attributes["class"].Value == "notice-comp-val") { baseP.InnerHtml = tenantName; } } } } result = html.DocumentNode.OuterHtml; } catch (Exception ex) { _logger.LogInformation($"通过邮件模板生成HTML异常,原因={ex.Message}"); throw ex; } return result; } #endregion #region 推送邮件 /// /// 推送邮件 /// /// 自定义邮件详情 /// 文件路径 /// 返回回执 private async Task PushEmail(EmailApiUserDefinedDto emailApiUserDefinedDto, string filePath) { CommonWebApiResult result = new CommonWebApiResult { succ = true }; List emailList = new List(); var emailUrl = _cache.GetAllDictData().GetAwaiter().GetResult() .FirstOrDefault(x => x.TypeCode == "url_set" && x.Code == "email_api_url")?.Value; if (emailUrl == null) throw Oops.Bah("字典未配置 url_set->email_api_url 请联系管理员"); System.IO.FileStream file = new System.IO.FileStream(filePath, FileMode.Open, FileAccess.Read); int SplitSize = 5242880;//5M分片长度 int index = 1; //序号 第几片 long StartPosition = 5242880 * (index - 1); long lastLens = file.Length - StartPosition;//真不知道怎么起命了,就这样吧 if (lastLens < 5242880) { SplitSize = (int)lastLens; } byte[] heByte = new byte[SplitSize]; file.Seek(StartPosition, SeekOrigin.Begin); //第一个参数是 起始位置 file.Read(heByte, 0, SplitSize); //第三个参数是 读取长度(剩余长度) file.Close(); string base64Str = Convert.ToBase64String(heByte); emailApiUserDefinedDto.Attaches.Add(new AttachesInfo { AttachName = Path.GetFileName(filePath), AttachContent = base64Str }); emailList.Add(emailApiUserDefinedDto); string strJoin = System.IO.File.ReadAllText(filePath); DateTime bDate = DateTime.Now; HttpResponseMessage res = null; try { res = await emailUrl.SetBody(emailList, "application/json").PostAsync(); } catch (Exception ex) { _logger.LogInformation($"发送邮件异常:{ex.Message}"); } DateTime eDate = DateTime.Now; TimeSpan ts = eDate.Subtract(bDate); var timeDiff = ts.TotalMilliseconds; _logger.LogInformation($"邮件上传完成 上传文件大小:{heByte.Length} 用时:{timeDiff}ms.,{strJoin}"); _logger.LogInformation($"发送邮件返回:{JSON.Serialize(res)}"); if (res != null && res.StatusCode == System.Net.HttpStatusCode.OK) { var userResult = await res.Content.ReadAsStringAsync(); var respObj = JsonConvert.DeserializeAnonymousType(userResult, new { Success = false, Message = string.Empty, Code = -9999, }); result.succ = respObj.Success; result.msg = respObj.Message; } return result; } #endregion #region 发送邮件 /// /// 发送邮件 /// /// BC任务主键 /// 返回回执 [HttpGet("/TaskManageBC/SendEmail")] public async Task SendEmail(string taskPKId) { if (string.IsNullOrWhiteSpace(taskPKId)) throw Oops.Oh($"BC任务主键不能为空"); var bcTaskInfo = await _taskBaseRepository.AsQueryable().FirstAsync(u => u.PK_ID == taskPKId); if (bcTaskInfo == null) { throw Oops.Oh($"任务主键{taskPKId}无法获取业务信息"); } var bcOrder = _taskBCInfoRepository.AsQueryable().First(a => a.TASK_ID == bcTaskInfo.PK_ID); if (bcOrder == null) throw Oops.Oh($"任务主键{taskPKId}无法获取BC业务信息"); return await GenerateSendEmail(bcOrder); } #endregion } /// /// 自定义邮件 /// public class EmailApiUserDefinedDto { /// /// 接收邮箱 /// public string SendTo { get; set; } /// /// 抄送 /// public string CCTo { get; set; } /// /// 邮件标题 /// public string Title { get; set; } /// /// 邮件正文 /// public string Body { get; set; } /// /// 账号 /// public string Account { get; set; } /// /// 密码(126邮箱需要在网站生成密文) /// public string Password { get; set; } /// /// SMTP服务器 /// public string Server { get; set; } /// /// SMTP端口 /// public int Port { get; set; } /// /// 发件SSL /// public bool UseSSL { get; set; } /// /// 附件 /// public List Attaches { get; set; } } }