diff --git a/.gitignore b/.gitignore index 55054247..a8f94cb5 100644 --- a/.gitignore +++ b/.gitignore @@ -63,3 +63,4 @@ bin-release/ /ds-wms-service/DS.WMS.OpApi/Properties/PublishProfiles/FolderProfile.pubxml.user /ds-wms-service/DS.WMS.OpApi/Logs/internal-nlog.txt /ds-wms-service/DS.WMS.OpApi/DS.WMS.OpApi.csproj.user +LinkAttach diff --git a/ds-wms-service/DS.Module.Core/Constants/MultiLanguageConst.cs b/ds-wms-service/DS.Module.Core/Constants/MultiLanguageConst.cs index d18aba59..945166ed 100644 --- a/ds-wms-service/DS.Module.Core/Constants/MultiLanguageConst.cs +++ b/ds-wms-service/DS.Module.Core/Constants/MultiLanguageConst.cs @@ -1454,6 +1454,15 @@ public static class MultiLanguageConst [Description("未能获取到相应BC业务数据")] public const string TaskBCInfoEmpty = "TaskBCInfoEmpty"; + + [Description("附件分类代码错误,请提供正确的分类代码")] + public const string TaskFileCategoryError = "TaskFileCategoryError"; + + [Description("任务主键{0}没有可下载的附件")] + public const string TaskFileEmpty = "TaskFileEmpty"; + + [Description("任务主键{0} 附件下载请求失败,请确认文件是否存在")] + public const string TaskFileNotExists = "TaskFileNotExists"; #endregion #region 邮件解析配置 diff --git a/ds-wms-service/DS.Module.Core/Enums/TaskPlat/TaskFileCategoryEnum.cs b/ds-wms-service/DS.Module.Core/Enums/TaskPlat/TaskFileCategoryEnum.cs index e7b08004..9fcc85d1 100644 --- a/ds-wms-service/DS.Module.Core/Enums/TaskPlat/TaskFileCategoryEnum.cs +++ b/ds-wms-service/DS.Module.Core/Enums/TaskPlat/TaskFileCategoryEnum.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.ComponentModel; namespace DS.Module.Core { diff --git a/ds-wms-service/DS.Module.Core/Filters/OperationLogFilter.cs b/ds-wms-service/DS.Module.Core/Filters/OperationLogFilter.cs index 6f0eb1a2..601afc36 100644 --- a/ds-wms-service/DS.Module.Core/Filters/OperationLogFilter.cs +++ b/ds-wms-service/DS.Module.Core/Filters/OperationLogFilter.cs @@ -16,7 +16,7 @@ namespace DS.Module.Core.Filters; /// /// 操作日志 过滤器 /// -public class OperationLogFilter: IAsyncActionFilter +public class OperationLogFilter : IAsyncActionFilter { private readonly IServiceProvider _serviceProvider; private readonly SqlSugarScope db; @@ -42,7 +42,7 @@ public class OperationLogFilter: IAsyncActionFilter var headers = httpRequest.Headers; var clientInfo = headers.ContainsKey("User-Agent") ? Parser.GetDefault().Parse(headers["User-Agent"]) : null; var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor; - var isWriteLog = false; + var isWriteLog = false; //请求异常时记录日志 if (!isRequestSucceed || AppSetting.app("Middleware", "RecordAccessLogs", "Enabled").ObjToBool()) @@ -50,7 +50,7 @@ public class OperationLogFilter: IAsyncActionFilter isWriteLog = true; } - var res = actionContext.Result?.GetType() == typeof(DataResult) ? actionContext.Result.ToJsonString() : ""; + //var res = actionContext.Result?.GetType() == typeof(DataResult) ? actionContext.Result.ToJsonString() : ""; if (isWriteLog) { var log = new SysLogOperation() @@ -66,11 +66,11 @@ public class OperationLogFilter: IAsyncActionFilter MethodName = actionDescriptor?.ActionName, ReqMethod = httpRequest.Method, Param = context.ActionArguments.Count < 1 ? "" : context.ActionArguments.ToJsonString(), - Result = actionContext.Result.ToJsonString(), + Result = actionContext?.Result is FileResult ? "(FileResult)" : actionContext.Result.ToJsonString(), ElapsedTime = sw.ElapsedMilliseconds, OpTime = DateTime.Now, }; - + await db.GetConnection(1288018625843826680).Insertable(log).ExecuteCommandAsync(); httpContext.Response.Headers["CheckTimeActionExecute"] = sw.ElapsedMilliseconds.ToString(); diff --git a/ds-wms-service/DS.Module.MultiLanguage/MultiLanguageMiddleware.cs b/ds-wms-service/DS.Module.MultiLanguage/MultiLanguageMiddleware.cs index 67ef712b..5d5cc08f 100644 --- a/ds-wms-service/DS.Module.MultiLanguage/MultiLanguageMiddleware.cs +++ b/ds-wms-service/DS.Module.MultiLanguage/MultiLanguageMiddleware.cs @@ -50,6 +50,7 @@ public class MultiLanguageMiddleware || context.Request.Path.Value.IndexOf("PrintTempFile", StringComparison.InvariantCultureIgnoreCase) > -1 || context.Request.Path.Value.IndexOf("GetOcrImg", StringComparison.InvariantCultureIgnoreCase) > -1 || context.Request.Path.Value.IndexOf("DownloadBookingOrClosingEDI", StringComparison.InvariantCultureIgnoreCase) > -1 + || context.Request.Path.Value.IndexOf("DownloadFile", StringComparison.InvariantCultureIgnoreCase) > -1 ) ) { diff --git a/ds-wms-service/DS.WMS.Core/TaskPlat/Interface/ITaskManageBaseService.cs b/ds-wms-service/DS.WMS.Core/TaskPlat/Interface/ITaskManageBaseService.cs index e28373cb..c9168c0b 100644 --- a/ds-wms-service/DS.WMS.Core/TaskPlat/Interface/ITaskManageBaseService.cs +++ b/ds-wms-service/DS.WMS.Core/TaskPlat/Interface/ITaskManageBaseService.cs @@ -22,5 +22,12 @@ namespace DS.WMS.Core.TaskPlat.Interface /// 任务主键数组 /// 人员信息列表 Task SetTaskOwner(long[] taskIds, List userInfo); + + /// + /// 根据任务ID获取附件信息 + /// + /// 任务Id + /// 附件分类代码 + Task<(string fileFullPath, string fileName)> GetTaskFileInfo(long taskId, string fileCategory); } } diff --git a/ds-wms-service/DS.WMS.Core/TaskPlat/Interface/ITaskManageService.cs b/ds-wms-service/DS.WMS.Core/TaskPlat/Interface/ITaskManageService.cs index 64b73b2b..790dd70e 100644 --- a/ds-wms-service/DS.WMS.Core/TaskPlat/Interface/ITaskManageService.cs +++ b/ds-wms-service/DS.WMS.Core/TaskPlat/Interface/ITaskManageService.cs @@ -58,5 +58,6 @@ namespace DS.WMS.Core.TaskPlat.Interface /// 业务类型 /// 要转交的人员信息列表 Task TransferTask(long bsno, TaskBaseTypeEnum taskBaseTypeEnum, List userInfos); + } } diff --git a/ds-wms-service/DS.WMS.Core/TaskPlat/Method/TaskManageBCService.cs b/ds-wms-service/DS.WMS.Core/TaskPlat/Method/TaskManageBCService.cs index 27d51985..9e7476e0 100644 --- a/ds-wms-service/DS.WMS.Core/TaskPlat/Method/TaskManageBCService.cs +++ b/ds-wms-service/DS.WMS.Core/TaskPlat/Method/TaskManageBCService.cs @@ -25,8 +25,6 @@ namespace DS.WMS.Core.TaskPlat.Method { } - - /// /// 通过任务主键获取BC详情 /// @@ -125,9 +123,9 @@ namespace DS.WMS.Core.TaskPlat.Method return DataResult.Success(result); } - public virtual async Task<(bool canCompelete, string? msg)> CompleteAsync(long taskId) - { - return (true, null); - } + //public virtual async Task<(bool canCompelete, string? msg)> CompleteAsync(long taskId) + //{ + // return (true, null); + //} } } diff --git a/ds-wms-service/DS.WMS.Core/TaskPlat/Method/TaskManageBaseService.cs b/ds-wms-service/DS.WMS.Core/TaskPlat/Method/TaskManageBaseService.cs index e49e4896..d08bb6fc 100644 --- a/ds-wms-service/DS.WMS.Core/TaskPlat/Method/TaskManageBaseService.cs +++ b/ds-wms-service/DS.WMS.Core/TaskPlat/Method/TaskManageBaseService.cs @@ -9,6 +9,8 @@ using Microsoft.Extensions.Logging; using SqlSugar; using System.Linq.Expressions; using System.Runtime.InteropServices; +using System.Text; +using System.Web; namespace DS.WMS.Core.TaskPlat.Method { @@ -102,12 +104,14 @@ namespace DS.WMS.Core.TaskPlat.Method /// /// 保存文件并返回文件完整路径 /// + /// 追加文件夹 /// 文件二进制流 /// 批次号 + /// 无拓展名的文件名 /// 文件类型 /// 附件类型 bcfiles-BC文件 sofile-订舱附件 /// 返回文件完整路径 - protected async Task SaveFile(byte[] fileBytes, string batchNo, + protected async Task SaveFile(string fileDictKey, byte[] fileBytes, string batchNo, string fileNameNoSuffix, PrintFileTypeEnum printFileType, string attachFileType = "sofiles") { var basePath = AppSetting.app(new string[] { "FileSettings", "BasePath" }); @@ -116,6 +120,9 @@ namespace DS.WMS.Core.TaskPlat.Method if (!string.IsNullOrWhiteSpace(attachFileType)) relativePath += $"\\{attachFileType}"; + if (!string.IsNullOrWhiteSpace(fileDictKey)) + relativePath += $"\\{fileDictKey}"; + string? dirAbs; if (string.IsNullOrEmpty(basePath)) { @@ -151,11 +158,13 @@ namespace DS.WMS.Core.TaskPlat.Method fileType = ".doc"; } - var id = SnowFlakeSingle.Instance.NextId(); - var fileSaveName = $"{id}{fileType}".ToLower(); + string curFileName = fileNameNoSuffix; + + //var id = SnowFlakeSingle.Instance.NextId(); + var fileSaveName = $"{curFileName}{fileType}"; - string fileRelaPath = Path.Combine(relativePath, fileSaveName).ToLower(); - string fileAbsPath = Path.Combine(dirAbs, fileSaveName).ToLower(); + string fileRelaPath = Path.Combine(relativePath, fileSaveName); + string fileAbsPath = Path.Combine(dirAbs, fileSaveName); if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { @@ -214,6 +223,65 @@ namespace DS.WMS.Core.TaskPlat.Method } #endregion + /// + /// 根据任务ID获取附件信息 + /// + /// 任务Id + /// 附件分类代码 + public async Task<(string fileFullPath, string fileName)> GetTaskFileInfo(long taskId, string fileCategory) + { + var tenantDb = saasDbService.GetBizDbScopeById(user.TenantId); + + var bcTaskInfo = await tenantDb.Queryable().Where(u => u.Id == taskId).FirstAsync(); + if (bcTaskInfo == null) + { + throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.DataQueryNoData))); + } + + TaskFileCategoryEnum fileCategoryEnum = TaskFileCategoryEnum.NONE; + + System.Enum.TryParse(fileCategory, out fileCategoryEnum); + + if (fileCategoryEnum == TaskFileCategoryEnum.NONE) + { + // 附件分类代码错误,请提供正确的分类代码 + throw new Exception(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskFileCategoryError))); + } + + string name = fileCategoryEnum.ToString(); + + var fileInfo = await tenantDb.Queryable().Where(u => u.TASK_PKID == taskId && u.FILE_CATEGORY == name).OrderByDescending(x => x.Id).FirstAsync(); + if (fileInfo == null) + { + // 附件分类代码错误,请提供正确的分类代码 + throw new Exception( + string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskFileCategoryError)), taskId) + ); + } + var basePath = AppSetting.app(new string[] { "FileSettings", "BasePath" }); + + string fileFullPath; + if (string.IsNullOrEmpty(basePath)) + { + fileFullPath = Path.Combine(environment.WebRootPath ?? "", fileInfo.FILE_PATH); + } + else + { + fileFullPath = Path.Combine(basePath, fileInfo.FILE_PATH); + + } + if (!File.Exists(fileFullPath)) + { + //任务主键{0} 附件下载请求失败,请确认文件是否存在 + throw new Exception( + string.Format(MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.TaskFileNotExists)), taskId) + ); + } + + var fileName = HttpUtility.UrlEncode(fileInfo.FILE_NAME, Encoding.GetEncoding("UTF-8"))!; + return (fileFullPath, fileName); + //return (new FileStream(fileFullPath, FileMode.Open), fileName); + } } } diff --git a/ds-wms-service/DS.WMS.Core/TaskPlat/Method/TaskManageService.cs b/ds-wms-service/DS.WMS.Core/TaskPlat/Method/TaskManageService.cs index d207fbef..e6997f58 100644 --- a/ds-wms-service/DS.WMS.Core/TaskPlat/Method/TaskManageService.cs +++ b/ds-wms-service/DS.WMS.Core/TaskPlat/Method/TaskManageService.cs @@ -1,6 +1,8 @@ using DS.Module.Core; using DS.Module.Core.Data; +using DS.Module.Core.Extensions; using DS.Module.Core.Helpers; +using DS.Module.DjyServiceStatus; using DS.Module.SqlSugar; using DS.Module.UserModule; using DS.WMS.Core.TaskPlat.Dtos; @@ -12,9 +14,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using SqlSugar; -using System.Runtime.InteropServices; -using DS.Module.Core.Extensions; -using DS.Module.DjyServiceStatus; namespace DS.WMS.Core.TaskPlat.Method @@ -371,8 +370,11 @@ namespace DS.WMS.Core.TaskPlat.Method fileCategory = TaskFileCategoryEnum.ADVISORY.ToString(); } - var fileFullName = await SaveFile(bytes, + var noExtensionFileName = Path.GetFileNameWithoutExtension(file.FileName); + var fileFullName = await SaveFile(taskInfo.Id.ToString(), + bytes, batchNo, + noExtensionFileName, GetFileType(file.FileName), attachFileType); @@ -460,8 +462,10 @@ namespace DS.WMS.Core.TaskPlat.Method } var noExtensionFileName = Path.GetFileNameWithoutExtension(modifyFile.FileName); - var fileFullName = await SaveFile(bytes, + var fileFullName = await SaveFile(taskInfo.Id.ToString(), + bytes, batchNo, + noExtensionFileName, GetFileType(modifyFile.FileName), attachFileType); @@ -488,7 +492,7 @@ namespace DS.WMS.Core.TaskPlat.Method //附件 if (info.Main.FileList != null && info.Main.FileList.Count > 0) { - info.Main.FileList.ForEach(async file => + var fileList = info.Main.FileList.Select(file => { var fileInfo = new TaskFileInfo(); @@ -536,9 +540,9 @@ namespace DS.WMS.Core.TaskPlat.Method fileInfo.FILE_NAME = fileModel.Name; fileInfo.FILE_TYPE = fileModel.Extension?.Replace(".", ""); } - - await tenantDb.Insertable(fileInfo).ExecuteCommandAsync(); - }); + return fileInfo; + }).ToList(); + await tenantDb.Insertable(fileList).ExecuteCommandAsync(); } #endregion @@ -546,7 +550,7 @@ namespace DS.WMS.Core.TaskPlat.Method //邮件 if (info.Main.EmailList != null && info.Main.EmailList.Count > 0) { - info.Main.EmailList.ForEach(async email => + var emailList = info.Main.EmailList.Select(email => { var emailInfo = new TaskEmail(); @@ -558,8 +562,9 @@ namespace DS.WMS.Core.TaskPlat.Method emailInfo.MAIL_PATH = email.MailPath; - await tenantDb.Insertable(emailInfo).ExecuteCommandAsync(); - }); + return emailInfo; + }).ToList(); + await tenantDb.Insertable(emailList).ExecuteCommandAsync(); } #endregion diff --git a/ds-wms-service/DS.WMS.Core/TaskPlat/Other/TaskFlowRuner.cs b/ds-wms-service/DS.WMS.Core/TaskPlat/Other/TaskFlowRuner.cs index c4cbd916..bcb55a32 100644 --- a/ds-wms-service/DS.WMS.Core/TaskPlat/Other/TaskFlowRuner.cs +++ b/ds-wms-service/DS.WMS.Core/TaskPlat/Other/TaskFlowRuner.cs @@ -1,6 +1,8 @@ using DS.Module.Core; using DS.Module.Core.Data; using DS.WMS.Core.TaskPlat.Entity; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Newtonsoft.Json; using SqlSugar; using System.Diagnostics; @@ -15,7 +17,7 @@ namespace DS.WMS.Core.TaskPlat { private readonly SqlSugarScopeProvider tenantDb = null!; private readonly IServiceProvider serviceProvider = null!; - + private readonly ILogger logger = null!; private TaskFlowRuner() { } /// @@ -27,6 +29,7 @@ namespace DS.WMS.Core.TaskPlat { this.tenantDb = tenantDb; this.serviceProvider = serviceProvider; + this.logger = serviceProvider.GetRequiredService>(); } /// /// 执行 @@ -35,7 +38,7 @@ namespace DS.WMS.Core.TaskPlat /// 任务Id /// 起始入参数据上下文 /// (执行日志Id,模块是否全部执行完成,模块执行结果是否全部为success) - public async Task<(long flowLogId, bool isAllComplete, bool isAllSuccess)> Run(TaskBaseTypeEnum taskBaseType, long taskId, TaskFlowDataContext dataContext) + public async Task<(long? flowLogId, bool isAllComplete, bool isAllSuccess)> Run(TaskBaseTypeEnum taskBaseType, long taskId, TaskFlowDataContext dataContext) { if (dataContext == null) { @@ -59,7 +62,9 @@ namespace DS.WMS.Core.TaskPlat IsSuccess = false, }; await tenantDb.Insertable(log).ExecuteCommandAsync(); - throw new Exception(msg); + logger.LogInformation(msg); + return (null, false, false); + //throw new Exception(msg); } var allConfigIdList = allConfigList.Select(x => x.Id); diff --git a/ds-wms-service/DS.WMS.TaskApi/Controllers/TaskManageController.cs b/ds-wms-service/DS.WMS.TaskApi/Controllers/TaskManageController.cs index db9516b9..463abcc6 100644 --- a/ds-wms-service/DS.WMS.TaskApi/Controllers/TaskManageController.cs +++ b/ds-wms-service/DS.WMS.TaskApi/Controllers/TaskManageController.cs @@ -183,6 +183,21 @@ public class TaskManageController : ApiController return DataResult.SuccessedWithDesc(nameof(MultiLanguageConst.OperationSuccess)); } + + /// + /// 根据任务ID下载附件 + /// + /// 任务主键 + /// 附件分类代码 + /// 返回数据流 + [HttpGet("DownloadFile")] + public async Task DownloadFile([FromQuery] long taskId, [FromQuery] string fileCategory = "BC") + { + (string fileFullPath, string fileName) = await taskManageService.GetTaskFileInfo(taskId, fileCategory); + + return PhysicalFile(fileFullPath, "application/octet-stream", fileName); + } + // /TaskManage/CreateBCTaskJob // /TaskManage/CreateDRAFTTaskJob // /TaskManage/CreateAdvisoryTaskJob diff --git a/ds-wms-service/DS.WMS.TaskApi/DS.WMS.TaskApi.csproj b/ds-wms-service/DS.WMS.TaskApi/DS.WMS.TaskApi.csproj index 83336c04..37958fa0 100644 --- a/ds-wms-service/DS.WMS.TaskApi/DS.WMS.TaskApi.csproj +++ b/ds-wms-service/DS.WMS.TaskApi/DS.WMS.TaskApi.csproj @@ -15,6 +15,7 @@ + @@ -23,4 +24,8 @@ + + + + diff --git a/ds-wms-service/ds-wms-service.sln b/ds-wms-service/ds-wms-service.sln index 22e9738c..7fe61eb2 100644 --- a/ds-wms-service/ds-wms-service.sln +++ b/ds-wms-service/ds-wms-service.sln @@ -60,14 +60,17 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DS.WMS.FinanceApi", "DS.WMS.FinanceApi\DS.WMS.FinanceApi.csproj", "{32B97A3A-C361-44F3-B417-5D08E9FD9624}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DS.WMS.TaskApi", "DS.WMS.TaskApi\DS.WMS.TaskApi.csproj", "{8DAE16A3-E249-4C86-BEEC-DA8429FD837C}" + ProjectSection(ProjectDependencies) = postProject + {B0351554-748F-4DF8-8C22-152646937EFE} = {B0351554-748F-4DF8-8C22-152646937EFE} + EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DS.Module.EmailModule", "DS.Module.EmailModule\DS.Module.EmailModule.csproj", "{4B51DCC1-62A5-49C5-978B-798E6B48F3C0}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DS.WMS.PrintApi", "DS.WMS.PrintApi\DS.WMS.PrintApi.csproj", "{274B1D18-A15A-4917-A567-6FDCD090D5B0}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DS.Module.OcrModule", "DS.Module.OcrModule\DS.Module.OcrModule.csproj", "{3EB9CA1E-5910-42A5-A64D-0CB435F6A64A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DS.Module.OcrModule", "DS.Module.OcrModule\DS.Module.OcrModule.csproj", "{3EB9CA1E-5910-42A5-A64D-0CB435F6A64A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DS.WMS.ContainerManagementApi", "DS.WMS.ContainerManagementApi\DS.WMS.ContainerManagementApi.csproj", "{7C3E248A-DF40-46AC-A8DF-224DD7C4EEF7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DS.WMS.ContainerManagementApi", "DS.WMS.ContainerManagementApi\DS.WMS.ContainerManagementApi.csproj", "{7C3E248A-DF40-46AC-A8DF-224DD7C4EEF7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution