From 0efde94a7473c297237ace7f8ce9f649a8561516 Mon Sep 17 00:00:00 2001 From: wanghu Date: Wed, 9 Sep 2026 16:27:17 +0800 Subject: [PATCH] =?UTF-8?q?=E9=99=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/YhCore.Service/Impl/FileService.cs | 13 ++++-- .../Api/Common/CommonController.cs | 40 +++++++++++++------ src/YhCore.WebApi/Startup.cs | 14 +++++-- src/YhCore.WebApi/appsettings.json | 2 +- 4 files changed, 50 insertions(+), 19 deletions(-) diff --git a/src/YhCore.Service/Impl/FileService.cs b/src/YhCore.Service/Impl/FileService.cs index 79d2cd6..70fd16d 100644 --- a/src/YhCore.Service/Impl/FileService.cs +++ b/src/YhCore.Service/Impl/FileService.cs @@ -214,9 +214,15 @@ namespace YhCore.Service.Impl if (string.IsNullOrEmpty(fileUrl)) return ""; - // 相对路径如 /upload/docprint/20260101/{guid}.jpg → Config.FilePath + 子路径 + // 新数据:fileurl 以 FILE_PATH 开头(如 /data/upload/docprint/20260101/{guid}.jpg)→ 剥前缀映射回 FILE_PATH。 + // 注意必须用未 TrimStart 的原始 fileUrl 比较(FILE_PATH 本身以 / 开头) + string fp = Config.FilePath; + if (!string.IsNullOrEmpty(fp) && fileUrl.StartsWith(fp, StringComparison.OrdinalIgnoreCase)) + return Path.Combine(fp, fileUrl.Substring(fp.Length).TrimStart('/').Replace('/', Path.DirectorySeparatorChar)); + + // 旧数据:相对路径如 /upload/docprint/20260101/{guid}.jpg(不含 FILE_PATH 前缀)→ StorageRoot + 子路径 var relative = fileUrl.TrimStart('/'); - string prefix = Config.FilePath; + const string prefix = "upload/"; if (relative.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) relative = relative.Substring(prefix.Length); @@ -229,7 +235,8 @@ namespace YhCore.Service.Impl if (!string.IsNullOrEmpty(Config.FilePath)) return Config.FilePath; - return Path.Combine(AppContext.BaseDirectory,Config.FilePath); + // 此分支仅在 FILE_PATH 未配置时执行(此时 Config.FilePath 为 null,不可再参与拼接) + return Path.Combine(AppContext.BaseDirectory, "upload"); } } } diff --git a/src/YhCore.WebApi/Controllers/Api/Common/CommonController.cs b/src/YhCore.WebApi/Controllers/Api/Common/CommonController.cs index ae7ddfb..99641fc 100644 --- a/src/YhCore.WebApi/Controllers/Api/Common/CommonController.cs +++ b/src/YhCore.WebApi/Controllers/Api/Common/CommonController.cs @@ -235,42 +235,58 @@ namespace YhCore.WebApi.Controllers.Api.Common /// /// 公用附件上传(旧 FileUpload,[NoAuth])。 - /// chunk 参数 → 分片保存返回 {code:1,type:"chunk",msg};fileName 参数 → 合并分片;否则单文件上传。 + /// 分片(chunk/chunkIndex + totalChunks>1)→ 分片保存返回 {code:1,type:"chunk",msg}; + /// 只带 fileName 不带文件 → 合并分片;带文件 → 单文件直传 + /// (前端单文件直传也会带 guid/chunkIndex=0/totalChunks=0/fileName,不得误入合并分支)。 + /// guid/chunk/fileName 兼容 query 与 form 两种形态(旧版读 Query)。 /// 落库 Common_UpFiles(TopicType=AppCode),返回 {fileurl,host,fileid,name,type}。 /// [HttpPost("FileUpload")] public async Task Upload() { string apptype = "docprint"; // 旧 WebHelper.AppType 固定 docprint - string guid = Request.Form["guid"]; - string chunk = Request.Form["chunk"]; - string fileName = Request.Form["fileName"]; + string guid = FormOrQuery("guid"); + string chunk = FormOrQuery("chunk"); // 旧契约分片序号 + string chunkIndex = FormOrQuery("chunkIndex"); // 前端现用分片序号 + string totalChunks = FormOrQuery("totalChunks"); + string fileName = FormOrQuery("fileName"); - if (!string.IsNullOrEmpty(chunk)) + var file = Request.Form.Files.FirstOrDefault(f => f.Name == "file") ?? Request.Form.Files.FirstOrDefault(); + bool multiChunk = int.TryParse(totalChunks, out var total) && total > 1; + bool isChunkReq = file != null + && (!string.IsNullOrEmpty(chunk) || (!string.IsNullOrEmpty(chunkIndex) && multiChunk)); + + if (isChunkReq) { - var chunkFile = Request.Form.Files.FirstOrDefault(f => f.Name == "file") ?? Request.Form.Files.FirstOrDefault(); - await _file.SaveChunkAsync(guid, chunk, chunkFile); + await _file.SaveChunkAsync(guid, string.IsNullOrEmpty(chunk) ? chunkIndex : chunk, file); return new { code = 1, type = "chunk", msg = "分片上传成功!" }; } FileObj url; - string errMsg = "上传失败!"; - if (string.IsNullOrEmpty(fileName)) + if (!string.IsNullOrEmpty(fileName) && file == null) { - url = await _file.SaveFileAsync(apptype, Request.Form.Files.FirstOrDefault()); + url = await _file.MergeSaveAsync(apptype, guid, fileName); // 合并分片 } else { - url = await _file.MergeSaveAsync(apptype, guid, fileName); + url = await _file.SaveFileAsync(apptype, file); // 单文件直传 } if (url == null) - throw new DException(errMsg); + throw new DException("上传失败!"); // 旧 WebHelper.AppCode == "1102" ? "1002" : AppCode → docprint 固定 1003 int serid = await _file.SaveEnclosureAsync(url, DocPrintConstants.AppCode.ToString()); return new { fileurl = url.fileurl, host = url.host, fileid = serid, name = url.filename, type = url.filetype }; } + /// 取表单/URL 参数(旧版读 Request["x"] 同时覆盖 Query+Form)。 + private string FormOrQuery(string name) + { + var v = Request.Form[name].ToString(); + if (!string.IsNullOrEmpty(v)) return v; + return Request.Query[name].ToString(); + } + /// 公用图片上传(旧 FileUploadImage,[NoAuth];多图,返回数组)。 [HttpPost("FileUploadImage")] public async Task UploadImg() diff --git a/src/YhCore.WebApi/Startup.cs b/src/YhCore.WebApi/Startup.cs index ca11202..66c38d4 100644 --- a/src/YhCore.WebApi/Startup.cs +++ b/src/YhCore.WebApi/Startup.cs @@ -175,9 +175,17 @@ namespace YhCore.WebApi .Bind(Configuration.GetSection("Swagger")); services.AddOptions() .Bind(Configuration); - // 静态门面(对齐 Java Config):文件路径由配置注入 - YhCore.Common.Config.Config.FilePath = Configuration["FILE_PATH"]; - YhCore.Common.Config.Config.FileWebPath = Configuration["FILE_WEB_PATH"]; + // 静态门面(对齐 Java Config):文件路径由配置注入。 + // FILE_PATH 必须以 / 结尾(旧约定:FileService 多处 FilePath + "{appType}/..." 直接拼接,缺斜杠会拼出坏路径); + // FILE_WEB_PATH 不带尾 /(拼接目标 fileurl 均以 / 开头,带尾斜杠会产生 //) + var configFilePath = Configuration["FILE_PATH"]; + YhCore.Common.Config.Config.FilePath = string.IsNullOrEmpty(configFilePath) + ? configFilePath + : configFilePath.TrimEnd('/').Replace('\\', '/') + "/"; + var configFileWebPath = Configuration["FILE_WEB_PATH"]; + YhCore.Common.Config.Config.FileWebPath = string.IsNullOrEmpty(configFileWebPath) + ? configFileWebPath + : configFileWebPath.TrimEnd('/'); // 审批单 PDF:wkhtmltopdf 可执行文件路径(空则用 PATH) YhCore.Common.Config.Config.WkHtmlToPdfPath = Configuration["wkhtmltopdf_path"]; diff --git a/src/YhCore.WebApi/appsettings.json b/src/YhCore.WebApi/appsettings.json index 0bca973..bc9cb33 100644 --- a/src/YhCore.WebApi/appsettings.json +++ b/src/YhCore.WebApi/appsettings.json @@ -10,7 +10,7 @@ "Redis": { "ConnectionString": "localhost:6379,defaultDatabase=0" }, - "FILE_PATH": "", + "FILE_PATH": "/data/upload/", "FILE_WEB_PATH": "", "wkhtmltopdf_path": "", "yh": {