using Furion; using Furion.DependencyInjection; using Furion.DistributedIDGenerator; using Furion.DynamicApiController; using Furion.FriendlyException; using Furion.JsonSerialization; using Furion.RemoteRequest.Extensions; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Myshipping.Application.ConfigOption; using Myshipping.Application.Entity; using Myshipping.Core; using Myshipping.Core.Service; using Org.BouncyCastle.Crypto; using StackExchange.Profiling.Internal; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net.Http; using System.Net.NetworkInformation; using System.Runtime.InteropServices; using System.Text; using System.Text.Json; using System.Threading.Tasks; using Yitter.IdGenerator; namespace Myshipping.Application { /// /// 订舱增值类服务 /// [ApiDescriptionSettings("Application", Name = "BookingValueAdded", Order = 9)] public class BookingValueAddedService : IBookingValueAddedService, IDynamicApiController, ITransient { private readonly ISysCacheService _cache; private readonly IDjyWebsiteAccountConfigService _webAccountConfig; private readonly ILogger _logger; private readonly SqlSugarRepository _bookingOrderRepository; private readonly SqlSugarRepository _bookingfile; const string CONST_MAPPING_BC_MODULE_ROUTE = "BC_DOWN_RT"; const string CONST_MAPPING_DRAFT_MODULE_ROUTE = "DRAFT_DOWN_RT"; const string CONST_FORMAT_BC_URL = "{0}_bc_down_url"; const string CONST_FORMAT_DRAFT_URL = "{0}_draft_down_url"; const string CONST_FORMAT_WEB = "{0}_Web"; public BookingValueAddedService(ISysCacheService cache, ILogger logger, SqlSugarRepository bookingOrderRepository, SqlSugarRepository bookingfile, IDjyWebsiteAccountConfigService webAccountConfig) { _cache = cache; _logger = logger; _bookingOrderRepository = bookingOrderRepository; _bookingfile = bookingfile; _webAccountConfig = webAccountConfig; } /// /// 批量BC下载 /// /// 订舱主键数组 /// 返回回执 [HttpPost("/BookingValueAdded/DownloadBookingConfirm")] public async Task DownloadBookingConfirm([FromBody]long[] bookingIds) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); List> taskList = new List>(); string batchNo = IDGen.NextID().ToString(); try { /* 1、订舱主键提取提单号、订舱编号,优先去提单号,其次订舱编号 2、根据不同的船公司调取单独的配置账户。 3、不同船公司对应不同的接口。 4、轮询异步调取接口等待返回接口。 5、成功后将文件链接存入附件表。 6、等待所有请求完成返回统计结果。 */ var list = _bookingOrderRepository.AsQueryable() .Where(a => bookingIds.Contains(a.Id)).ToList(); if (list.Count != bookingIds.Length) throw Oops.Oh($"订舱信息获取失败,订舱信息不存在或已作废"); var noList = bookingIds.Select((a, idx) => new { no = idx + 1, id = a }).ToList(); foreach (var bk in list) { var sortNo = noList.FirstOrDefault(a=>a.id == bk.Id).no; taskList.Add(Task.Run(() => InnerDownloadBookingConfirm(bk, batchNo, sortNo))); } Task.WaitAll(taskList.ToArray()); result.succ = true; result.msg = "批量下载BC成功"; var downResultList = taskList.Select(x => x.Result).ToList(); if (downResultList.Any(x => !x.succ)) { result.succ = false; result.msg = "BC下载失败"; } else { result.succ = true; result.msg = downResultList.FirstOrDefault().msg; } result.ext = downResultList; var succ = downResultList.Count(x => x.succ); var fail = downResultList.Count(x => !x.succ); if (succ > 0) result.batchTotal = succ.ToString(); if(fail > 0) { if (succ > 0) result.batchTotal = result.batchTotal+"/"+ fail.ToString(); result.batchTotal = "/" + fail.ToString(); } } catch (Exception ex) { result.succ = false; result.msg = $"批量BC下载异常,原因:{ex.Message}"; } return result; } #region 单票下载BC /// /// 单票下载BC /// /// 订舱详情 /// 批次号 /// 请求顺序号 /// 返回回执 private async Task InnerDownloadBookingConfirm(BookingOrder bookingOrder,string batchNo, int sortNo) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); result.bno = bookingOrder.MBLNO; try { /* 1、根据船公司代码匹配船公司映射。 2、BC和DRAFT是分别2个请求地址。 3、生成请求报文。 4、请求相应的链接。 5、返回成功写入附件。 */ if (string.IsNullOrWhiteSpace(bookingOrder.MBLNO)) { if (!string.IsNullOrWhiteSpace(bookingOrder.CUSTNO)) { result.bno = $"订 {bookingOrder.CUSTNO}"; } else { result.bno = $"NO.{sortNo}"; } throw Oops.Bah($"主提单号不能为空"); } var bcOrDraftRouteCfg = _cache.GetAllMappingCarrier().GetAwaiter().GetResult() .FirstOrDefault(t => t.Module.Equals(CONST_MAPPING_BC_MODULE_ROUTE, StringComparison.OrdinalIgnoreCase) && t.Code.Equals(bookingOrder.CARRIERID?.Trim(), StringComparison.OrdinalIgnoreCase)); _logger.LogInformation("提单号【{mbl}】根据订舱的船公司代码{ca} 提取船公司映射完成,结果={rlt}", bookingOrder.MBLNO, bookingOrder.CARRIERID, bcOrDraftRouteCfg); if (bcOrDraftRouteCfg == null) { _logger.LogInformation("提单号{mbl} 根据订舱的船公司代码{ca} 提取船公司映射失败", bookingOrder.MBLNO, bookingOrder.CARRIERID); throw Oops.Bah($"船公司={bookingOrder.CARRIERID} 暂不支持BC下载"); } string urlKey = string.Format(CONST_FORMAT_BC_URL, bcOrDraftRouteCfg.MapCode.ToLower()); var bcUrl = _cache.GetAllDictData().GetAwaiter().GetResult() .FirstOrDefault(x => x.TypeCode == "url_set" && x.Code.Equals(urlKey, StringComparison.OrdinalIgnoreCase))?.Value; _logger.LogInformation("提单号{mbl} 根据订舱的船公司代码{ca} 提取Draft下载URL完成,结果={rlt}", bookingOrder.MBLNO, bookingOrder.CARRIERID, bcUrl); if (string.IsNullOrWhiteSpace(bcUrl)) { _logger.LogInformation("提单号{0} 根据订舱的船公司代码{1} 提取BC下载URL失败,未取到配置key={key}", bookingOrder.MBLNO, bookingOrder.CARRIERID, urlKey); throw Oops.Bah($"船公司={bookingOrder.CARRIERID} 未配置请求地址{urlKey} 请联系管理员"); } string webKey = string.Format(CONST_FORMAT_WEB, bcOrDraftRouteCfg.MapCode.ToLower()); //获取个人对应的账户,这里GetAccountConfig逻辑优先取个人,个人没有配置取公司对应配置 var userWebAccountConfig = _webAccountConfig.GetAccountConfig(webKey, UserManager.UserId).GetAwaiter() .GetResult(); _logger.LogInformation("批次={no} 获取获取网站的账户完成,result={Num}", batchNo, JSON.Serialize(userWebAccountConfig)); if (userWebAccountConfig == null) throw Oops.Oh($" 未配置个人或公司网站账户,网站{webKey}"); BCOrDraftRequestDto requestDto = new BCOrDraftRequestDto { user_key = App.Configuration["BCOrDraftUserKey"], user_secret = App.Configuration["BCOrDraftUserSecret"], web_user = userWebAccountConfig.Account?.Trim(), web_psw = userWebAccountConfig.Password?.Trim(), bno = bookingOrder.MBLNO, is_parse = false }; _logger.LogInformation("批次={no} json={json} 请求BC远端下载开始", batchNo, JSON.Serialize(requestDto)); DateTime bDate = DateTime.Now; //开始请求BC var rlt = await ExcuteBCDownload(bcUrl, requestDto, batchNo); DateTime eDate = DateTime.Now; TimeSpan ts = eDate.Subtract(bDate); var timeDiff = ts.TotalMilliseconds; _logger.LogInformation("批次={no} result={result} 请求BC远端下载结束 耗时:{timeDiff}ms. ", batchNo, JSON.Serialize(rlt),timeDiff); if (rlt.code == 200) { _logger.LogInformation("批次={no} 下载文件成功,转存本地", batchNo); string currFilePath = rlt.data.FirstOrDefault().path; string fileTypeCode = "bc"; string fileTypeName = "Booking Confirmation"; //读取文件配置 var fileCfg = App.GetOptions(); string relativePath = $"{fileCfg.relativePath}\\bcfiles\\{bookingOrder.Id}"; string filePath = $"{(!string.IsNullOrWhiteSpace(fileCfg.basePath) ? fileCfg.basePath : App.WebHostEnvironment.WebRootPath)}\\{relativePath}"; string fileFullName = $"{filePath}\\{new System.IO.FileInfo(currFilePath).Name}"; if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { relativePath = relativePath.Replace("\\", "/"); filePath = filePath.Replace("\\", "/"); fileFullName = fileFullName.Replace("\\", "/"); } _logger.LogInformation("批次={no} 生成文件保存路径完成 路由={filePath} 服务器系统={system}", batchNo, filePath, RuntimeInformation.OSDescription); //预先创建目录 if (!Directory.Exists(filePath)) { Directory.CreateDirectory(filePath); } var bcStream = await currFilePath.GetAsStreamAsync(); using (var fileStream = File.Create(fileFullName)) { await bcStream.CopyToAsync(fileStream); } _logger.LogInformation("批次={no} 完成文件保存 filepath={path}", batchNo, fileFullName); string bookFilePath = string.Empty; if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { bookFilePath = System.Text.RegularExpressions.Regex.Match(fileFullName, relativePath.Replace("/", "\\/") + ".*").Value; } else { bookFilePath = System.Text.RegularExpressions.Regex.Match(fileFullName, relativePath.Replace("\\", "\\\\") + ".*").Value; } //这里先写入附件表 await SaveEDIFile(bookingOrder.Id, bookFilePath, new System.IO.FileInfo(currFilePath).Name, fileTypeCode, fileTypeName); result.succ = true; result.msg = "BC下载成功"; } else { result.succ = false; result.msg = $"BC下载失败,{rlt.msg}"; } } catch (Exception ex) { result.succ = false; result.msg = $"BC下载失败,{ex.Message}"; } return result; } #endregion /// /// 异步写入订舱附件表 /// /// 订舱ID /// 文件路径 /// 文件名 /// 附件类型代码 /// 附件类型名称 /// [NonAction] private async Task SaveEDIFile(long boookId, string FilePath, string fileName, string fileTypeCode = "bc", string fileTypeName = "Booking Confirmation") { /* 直接将附件信息写入附件表 */ //EDI文件 var bookFile = new BookingFile { Id = YitIdHelper.NextId(), FileName = fileName, FilePath = FilePath, TypeCode = fileTypeCode, TypeName = fileTypeName, BookingId = boookId, }; await _bookingfile.InsertAsync(bookFile); } /// /// 批量Draft下载 /// /// 订舱主键数组 /// [HttpPost("/BookingValueAdded/DownloadDraft")] public async Task DownloadDraft([FromBody]long[] bookingIds) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); List> taskList = new List>(); string batchNo = IDGen.NextID().ToString(); try { /* 1、订舱主键提取提单号、订舱编号,优先去提单号,其次订舱编号 2、根据不同的船公司调取单独的配置账户。 3、不同船公司对应不同的接口。 4、轮询异步调取接口等待返回接口。 5、成功后将文件链接存入附件表。 6、等待所有请求完成返回统计结果。 */ var list = _bookingOrderRepository.AsQueryable() .Where(a => bookingIds.Contains(a.Id)).ToList(); if (list.Count != bookingIds.Length) throw Oops.Oh($"订舱信息获取失败,订舱信息不存在或已作废"); var noList = bookingIds.Select((a, idx) => new { no = idx + 1, id = a }).ToList(); foreach (var bk in list) { var sortNo = noList.FirstOrDefault(a=>a.id == bk.Id).no; taskList.Add(Task.Run(() => InnerDownloadDraft(bk, batchNo, sortNo))); } Task.WaitAll(taskList.ToArray()); result.succ = true; result.msg = "下载Draft成功"; var downResultList = taskList.Select(x => x.Result).ToList(); if (downResultList.Any(x => !x.succ)) { result.succ = false; result.msg = "Draft下载失败"; } else { result.succ = true; result.msg = downResultList.FirstOrDefault().msg; } result.ext = downResultList; var succ = downResultList.Count(x => x.succ); var fail = downResultList.Count(x => !x.succ); if (succ > 0) result.batchTotal = succ.ToString(); if (fail > 0) { if (succ > 0) result.batchTotal = result.batchTotal + "/" + fail.ToString(); result.batchTotal = "/" + fail.ToString(); } } catch (Exception ex) { result.succ = false; result.msg = $"下载Draft异常,原因:{ex.Message}"; } return result; } #region 单票下载BC /// /// 单票下载BC /// /// 订舱详情 /// 批次号 /// 请求顺序号 /// 返回回执 private async Task InnerDownloadDraft(BookingOrder bookingOrder, string batchNo,int sortNo) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); result.bno = bookingOrder.MBLNO; try { /* 1、根据船公司代码匹配船公司映射。 2、BC和DRAFT是分别2个请求地址。 3、生成请求报文。 4、请求相应的链接。 5、返回成功写入附件。 */ if(bookingOrder.CARRIERID.Equals("ESL", StringComparison.OrdinalIgnoreCase)) { if(string.IsNullOrWhiteSpace(bookingOrder.TMBLNO)) { if (!string.IsNullOrWhiteSpace(bookingOrder.CUSTNO)) { result.bno = $"订 {bookingOrder.CUSTNO}"; } else if (string.IsNullOrWhiteSpace(bookingOrder.MBLNO)) { result.bno = $"NO.{sortNo}"; } throw Oops.Bah($"EP号不能为空"); } } else { if (string.IsNullOrWhiteSpace(bookingOrder.MBLNO)) { if (!string.IsNullOrWhiteSpace(bookingOrder.CUSTNO)) { result.bno = $"订 {bookingOrder.CUSTNO}"; } else { result.bno = $"NO.{sortNo}"; } throw Oops.Bah($"主提单号不能为空"); } } var bcOrDraftRouteCfg = _cache.GetAllMappingCarrier().GetAwaiter().GetResult() .FirstOrDefault(t => t.Module.Equals(CONST_MAPPING_DRAFT_MODULE_ROUTE, StringComparison.OrdinalIgnoreCase) && t.Code.Equals(bookingOrder.CARRIERID?.Trim(), StringComparison.OrdinalIgnoreCase)); _logger.LogInformation("提单号{mbl} 根据订舱的船公司代码{ca} 提取船公司映射完成,结果={rlt}", bookingOrder.MBLNO, bookingOrder.CARRIERID, bcOrDraftRouteCfg); if (bcOrDraftRouteCfg == null) { _logger.LogInformation("提单号{0} 根据订舱的船公司代码{1} 提取船公司映射失败", bookingOrder.MBLNO, bookingOrder.CARRIERID); throw Oops.Bah($"船公司={bookingOrder.CARRIERID} 暂不支持Draft下载"); } string urlKey = string.Format(CONST_FORMAT_DRAFT_URL, bcOrDraftRouteCfg.MapCode.ToLower()); var bcUrl = _cache.GetAllDictData().GetAwaiter().GetResult() .FirstOrDefault(x => x.TypeCode == "url_set" && x.Code.Equals(urlKey, StringComparison.OrdinalIgnoreCase))?.Value; _logger.LogInformation("提单号{mbl} 根据订舱的船公司代码{ca} 提取DRAFT下载URL完成,结果={rlt}", bookingOrder.MBLNO, bookingOrder.CARRIERID, bcUrl); if (string.IsNullOrWhiteSpace(bcUrl)) { _logger.LogInformation("提单号{0} 根据订舱的船公司代码{1} 提取BC下载URL失败,未取到配置key={key}", bookingOrder.MBLNO, bookingOrder.CARRIERID, urlKey); throw Oops.Bah($"船公司={bookingOrder.CARRIERID} 未配置请求地址{urlKey} 请联系管理员"); } string webKey = string.Format(CONST_FORMAT_WEB, bcOrDraftRouteCfg.MapCode.ToLower()); //获取个人对应的账户,这里GetAccountConfig逻辑优先取个人,个人没有配置取公司对应配置 var userWebAccountConfig = _webAccountConfig.GetAccountConfig(webKey, UserManager.UserId).GetAwaiter() .GetResult(); _logger.LogInformation("批次={no} 获取获取网站的账户完成,result={Num}", batchNo, JSON.Serialize(userWebAccountConfig)); if (userWebAccountConfig == null) throw Oops.Oh($" 未配置个人或公司网站账户,网站{webKey}"); string downloadFilePathRlt = string.Empty; string erroMsg = string.Empty; if(bcOrDraftRouteCfg.MapCode.Trim().Equals("ESL", StringComparison.OrdinalIgnoreCase)) { ESLDraftRequestDto requestDto = new ESLDraftRequestDto { u = userWebAccountConfig.Account?.Trim(), p = userWebAccountConfig.Password?.Trim(), ep_code = bookingOrder.TMBLNO?.Trim().ToUpper(), }; _logger.LogInformation("批次={no} json={json} 请求Draft远端下载开始", batchNo, JSON.Serialize(requestDto)); DateTime bDate = DateTime.Now; //开始请求BC var rlt = await ExcuteESLDraftDownload(bcUrl, requestDto, batchNo); DateTime eDate = DateTime.Now; TimeSpan ts = eDate.Subtract(bDate); var timeDiff = ts.TotalMilliseconds; _logger.LogInformation("批次={no} result={result} 请求Draft远端下载结束 耗时:{timeDiff}ms. ", batchNo, JSON.Serialize(rlt), timeDiff); if (rlt.status == 1) { downloadFilePathRlt = rlt.data.api_path; } else { erroMsg = rlt.message; } } else { BCOrDraftRequestDto requestDto = new BCOrDraftRequestDto { user_key = App.Configuration["BCOrDraftUserKey"], user_secret = App.Configuration["BCOrDraftUserSecret"], web_user = userWebAccountConfig.Account?.Trim(), web_psw = userWebAccountConfig.Password?.Trim(), bno = bookingOrder.MBLNO, is_parse = false }; _logger.LogInformation("批次={no} json={json} 请求Draft远端下载开始", batchNo, JSON.Serialize(requestDto)); DateTime bDate = DateTime.Now; //开始请求BC var rlt = await ExcuteDraftDownload(bcUrl, requestDto, batchNo); DateTime eDate = DateTime.Now; TimeSpan ts = eDate.Subtract(bDate); var timeDiff = ts.TotalMilliseconds; _logger.LogInformation("批次={no} result={result} 请求Draft远端下载结束 耗时:{timeDiff}ms. ", batchNo, JSON.Serialize(rlt), timeDiff); if (rlt.code == 200) { downloadFilePathRlt = rlt.data.FirstOrDefault().path; } else { erroMsg = rlt.msg; } } if (!string.IsNullOrWhiteSpace(downloadFilePathRlt)) { _logger.LogInformation("批次={no} 下载文件成功,转存本地", batchNo); string currFilePath = downloadFilePathRlt; string fileTypeCode = "draft"; string fileTypeName = "Draft"; //读取文件配置 var fileCfg = App.GetOptions(); string relativePath = $"{fileCfg.relativePath}\\draftfiles\\{bookingOrder.Id}"; string filePath = $"{(!string.IsNullOrWhiteSpace(fileCfg.basePath) ? fileCfg.basePath : App.WebHostEnvironment.WebRootPath)}\\{relativePath}"; string fileFullName = $"{filePath}\\{new System.IO.FileInfo(currFilePath).Name}"; if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { relativePath = relativePath.Replace("\\", "/"); filePath = filePath.Replace("\\", "/"); fileFullName = fileFullName.Replace("\\", "/"); } _logger.LogInformation("批次={no} 生成文件保存路径完成 路由={filePath} 服务器系统={system}", batchNo, filePath, RuntimeInformation.OSDescription); //预先创建目录 if (!Directory.Exists(filePath)) { Directory.CreateDirectory(filePath); } var bcStream = await currFilePath.GetAsStreamAsync(); using (var fileStream = File.Create(fileFullName)) { await bcStream.CopyToAsync(fileStream); } _logger.LogInformation("批次={no} 完成文件保存 filepath={path}", batchNo, fileFullName); string bookFilePath = string.Empty; if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { bookFilePath = System.Text.RegularExpressions.Regex.Match(fileFullName, relativePath.Replace("/", "\\/") + ".*").Value; } else { bookFilePath = System.Text.RegularExpressions.Regex.Match(fileFullName, relativePath.Replace("\\", "\\\\") + ".*").Value; } //这里先写入附件表 await SaveEDIFile(bookingOrder.Id, bookFilePath, new System.IO.FileInfo(currFilePath).Name, fileTypeCode, fileTypeName); result.succ = true; result.msg = "Draft下载成功"; } else { result.succ = false; result.msg = $"Draft下载失败,原因={erroMsg}"; } } catch (Exception ex) { result.succ = false; result.msg = $"Draft下载失败,原因:{ex.Message}"; } return result; } #endregion #region BC请求远端下载 /// /// BC请求远端下载 /// /// 请求URL /// 请求详情 /// 批次号 /// 返回结果 [NonAction] private async Task ExcuteBCDownload(string url, BCOrDraftRequestDto info, string batchNo) { BCAPIBaseResult model = null; /* 1、填充请求的类,并生成JSON报文 2、POST请求接口,并记录回执。 3、返回信息。 */ try { _logger.LogInformation("批次={no} 对应请求报文 request={res}", batchNo, JSON.Serialize(info)); var res = await url.OnClientCreating(client => { // client 为 HttpClient 对象 client.Timeout = TimeSpan.FromMinutes(15); // 设置超时时间 15分钟 }).SetHttpMethod(HttpMethod.Post) .SetBody(JSON.Serialize(info), "application/json") .SetContentEncoding(Encoding.UTF8) .PostAsync(); _logger.LogInformation("批次={no} 对应请求报文完成 res={res}", batchNo, JSON.Serialize(res)); if (res.StatusCode == System.Net.HttpStatusCode.OK) { var userResult = await res.Content.ReadAsStringAsync(); System.Text.Json.JsonSerializerOptions jsonOptions = new JsonSerializerOptions(); jsonOptions.Converters.Add(new DateTimeJsonConverter("yyyy-MM-dd HH:mm:ss")); model = JSON.Deserialize(userResult, jsonOptions); } } catch (Exception ex) { //写日志 if (ex is HttpRequestException) throw Oops.Oh(10000002); } return model; } #endregion #region Draft请求远端下载 /// /// Draft请求远端下载 /// /// 请求URL /// 请求详情 /// 批次号 /// 返回结果 [NonAction] private async Task ExcuteDraftDownload(string url, BCOrDraftRequestDto info, string batchNo) { DraftAPIBaseResult model = null; /* 1、填充请求的类,并生成JSON报文 2、POST请求接口,并记录回执。 3、返回信息。 */ try { _logger.LogInformation("批次={no} 对应请求报文 request={res}", batchNo, JSON.Serialize(info)); var res = await url.OnClientCreating(client => { // client 为 HttpClient 对象 client.Timeout = TimeSpan.FromMinutes(15); // 设置超时时间 15分钟 }).SetHttpMethod(HttpMethod.Post) .SetBody(JSON.Serialize(info), "application/json") .SetContentEncoding(Encoding.UTF8) .PostAsync(); _logger.LogInformation("批次={no} 对应请求报文完成 res={res}", batchNo, JSON.Serialize(res)); if (res.StatusCode == System.Net.HttpStatusCode.OK) { var userResult = await res.Content.ReadAsStringAsync(); System.Text.Json.JsonSerializerOptions jsonOptions = new JsonSerializerOptions(); jsonOptions.Converters.Add(new DateTimeJsonConverter("yyyy-MM-dd HH:mm:ss")); model = JSON.Deserialize(userResult, jsonOptions); } } catch (Exception ex) { //写日志 if (ex is HttpRequestException) throw Oops.Oh(10000002); } return model; } #endregion #region ESL Draft请求远端下载 /// /// ESL Draft请求远端下载 /// 由于现有的ESL和TSL接口不一致,需要提供单独的POST方法 /// /// 请求URL /// 请求详情 /// 批次号 /// 返回结果 [NonAction] private async Task ExcuteESLDraftDownload(string url, ESLDraftRequestDto info, string batchNo) { ESLDraftAPIBaseResult model = null; /* 1、填充请求的类,并生成JSON报文 2、POST请求接口,并记录回执。 3、返回信息。 */ try { _logger.LogInformation("批次={no} 对应请求报文 request={res}", batchNo, JSON.Serialize(info)); var res = await url.OnClientCreating(client => { // client 为 HttpClient 对象 client.Timeout = TimeSpan.FromMinutes(15); // 设置超时时间 15分钟 }).SetHttpMethod(HttpMethod.Post) .SetBody(JSON.Serialize(info), "application/json") .SetContentEncoding(Encoding.UTF8) .PostAsync(); _logger.LogInformation("批次={no} 对应请求报文完成 res={res}", batchNo, JSON.Serialize(res)); if (res.StatusCode == System.Net.HttpStatusCode.OK) { var userResult = await res.Content.ReadAsStringAsync(); model = JSON.Deserialize(userResult); } } catch (Exception ex) { //写日志 if (ex is HttpRequestException) throw Oops.Oh(10000002); } return model; } #endregion /// /// 到港时间更新 /// /// 订舱主键数组 /// 返回回执 [HttpPost("/BookingValueAdded/CheckUpdateETA")] public async Task CheckUpdateETA([FromBody] long[] bookingIds) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); try { /* 1、订舱主键提取提单号、订舱编号,优先去提单号,其次订舱编号 2、根据不同的船公司调取单独的配置账户。 3、不同船公司对应不同的接口。 4、轮询异步调取接口等待返回接口。 5、成功后将文件链接存入附件表。 6、等待所有请求完成返回统计结果。 */ result.succ = true; result.msg = "批量执行成功"; //result.ext = id; } catch (Exception ex) { result.succ = false; result.msg = $"批量下载Draft异常,原因:{ex.Message}"; } return result; } /// /// 舱位分配查询 /// /// 订舱主键数组 /// 返回回执 [HttpPost("/BookingValueAdded/CheckUpdateManifestNo")] public async Task CheckUpdateManifestNo([FromBody] long[] bookingIds) { TaskManageOrderResultDto result = new TaskManageOrderResultDto(); try { /* 1、订舱主键提取提单号、订舱编号,优先去提单号,其次订舱编号 2、根据不同的船公司调取单独的配置账户。 3、不同船公司对应不同的接口。 4、轮询异步调取接口等待返回接口。 5、成功后将文件链接存入附件表。 6、等待所有请求完成返回统计结果。 */ result.succ = true; result.msg = "批量执行成功"; //result.ext = id; } catch (Exception ex) { result.succ = false; result.msg = $"批量下载Draft异常,原因:{ex.Message}"; } return result; } } public class DateTimeJsonConverter : System.Text.Json.Serialization.JsonConverter { private readonly string _dateFormatString; public DateTimeJsonConverter() { _dateFormatString = "yyyy-MM-dd HH:mm:ss"; } public DateTimeJsonConverter(string dateFormatString) { _dateFormatString = dateFormatString; } public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return DateTime.Parse(reader.GetString()); } public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) { writer.WriteStringValue(value.ToUniversalTime().ToString(_dateFormatString)); } } }