StandardInterface/MES.Service/service/QC/LljService.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
StandardInterface/MESApplication/Controllers/QC/LljController.cs | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
StandardInterface/MES.Service/service/QC/LljService.cs
@@ -313,10 +313,18 @@ public List<QamftpDto> GetAttachments(string releaseNo) { if (string.IsNullOrEmpty(releaseNo)) { throw new ArgumentException("检验单号不能为空"); } var db = SqlSugarHelper.GetInstance(); try { return db.Queryable<MesQamftp>() .Where(x => x.ReleaseNo == releaseNo) .OrderBy(x => x.Fdate, OrderByType.Desc) // .ThenBy(x => x.CreateDate, OrderByType.Desc) .Select(x => new QamftpDto { Id = x.Id, @@ -336,6 +344,168 @@ ItemId = x.ItemId }).ToList(); } catch (Exception ex) { throw new Exception($"查询附件信息失败: {ex.Message}"); } } public byte[] GetFtpFile(string itemNo, string fileName, string ftpServer) { // 参数验证 if (string.IsNullOrEmpty(itemNo) || string.IsNullOrEmpty(fileName) || string.IsNullOrEmpty(ftpServer)) { throw new ArgumentException("参数不能为空: itemNo, fileName, ftpServer"); } string ftpUser = "hm_ftp"; string ftpPwd = "dell_123"; // 标准化FTP服务器地址 string normalizedServer = NormalizeFtpServer(ftpServer); // 构建FTP文件路径 string ftpPath = $"{normalizedServer}/IQC/{itemNo}/{fileName}"; try { var request = (System.Net.FtpWebRequest)System.Net.WebRequest.Create(ftpPath); request.Method = System.Net.WebRequestMethods.Ftp.DownloadFile; request.Credentials = new System.Net.NetworkCredential(ftpUser, ftpPwd); request.UseBinary = true; request.UsePassive = false; request.Timeout = 30000; // 30秒超时 request.ReadWriteTimeout = 30000; using (var response = (System.Net.FtpWebResponse)request.GetResponse()) using (var ftpStream = response.GetResponseStream()) using (var ms = new System.IO.MemoryStream()) { if (ftpStream == null) { throw new Exception("FTP响应流为空"); } ftpStream.CopyTo(ms); var fileBytes = ms.ToArray(); if (fileBytes.Length == 0) { return null; // 文件为空或不存在 } return fileBytes; } } catch (System.Net.WebException ex) { if (ex.Response is System.Net.FtpWebResponse ftpResponse) { switch (ftpResponse.StatusCode) { case System.Net.FtpStatusCode.ActionNotTakenFileUnavailable: return null; // 文件不存在 case System.Net.FtpStatusCode.NotLoggedIn: throw new Exception("FTP认证失败,请检查用户名和密码"); case System.Net.FtpStatusCode.ActionNotTakenFilenameNotAllowed: throw new Exception("文件名不被允许或路径无效"); default: throw new Exception($"FTP错误 ({ftpResponse.StatusCode}): {ftpResponse.StatusDescription}"); } } // 处理超时和网络错误 if (ex.Status == System.Net.WebExceptionStatus.Timeout) { throw new Exception("FTP连接超时,请稍后重试"); } throw new Exception($"FTP连接失败: {ex.Message}"); } catch (Exception ex) { throw new Exception($"获取文件失败: {ex.Message}"); } } private string NormalizeFtpServer(string ftpServer) { if (string.IsNullOrEmpty(ftpServer)) { throw new ArgumentException("FTP服务器地址不能为空"); } // 确保以ftp://开头 string normalizedServer = ftpServer.StartsWith("ftp://") ? ftpServer : $"ftp://{ftpServer}"; // 特殊处理已知服务器地址 if (normalizedServer == "ftp://36.26.21.214") { normalizedServer = "ftp://36.26.21.214:21"; } else if (!normalizedServer.Contains(":") && normalizedServer.StartsWith("ftp://")) { normalizedServer += ":21"; // 默认FTP端口 } // 开发环境使用本地服务器 normalizedServer = "ftp://192.168.1.22:21"; return normalizedServer; } public string GetContentType(string fileName) { if (string.IsNullOrEmpty(fileName)) return "application/octet-stream"; var extension = System.IO.Path.GetExtension(fileName).ToLower(); return extension switch { // PDF文件 ".pdf" => "application/pdf", // 图片文件 ".jpg" or ".jpeg" => "image/jpeg", ".png" => "image/png", ".gif" => "image/gif", ".bmp" => "image/bmp", ".webp" => "image/webp", ".svg" => "image/svg+xml", ".ico" => "image/x-icon", // 文本文件 ".txt" => "text/plain; charset=utf-8", ".log" => "text/plain; charset=utf-8", ".md" => "text/markdown; charset=utf-8", ".csv" => "text/csv; charset=utf-8", ".xml" => "text/xml; charset=utf-8", ".json" => "application/json; charset=utf-8", // Office文档 ".doc" => "application/msword", ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document", ".xls" => "application/vnd.ms-excel", ".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ".ppt" => "application/vnd.ms-powerpoint", ".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation", // 压缩文件 ".zip" => "application/zip", ".rar" => "application/x-rar-compressed", ".7z" => "application/x-7z-compressed", // 其他常见格式 ".dwg" => "application/acad", ".dxf" => "application/dxf", ".step" or ".stp" => "application/step", ".iges" or ".igs" => "application/iges", // 默认二进制流 _ => "application/octet-stream" }; } public int saveItem(LLJDto rkjDto) { var items = rkjDto.items; StandardInterface/MESApplication/Controllers/QC/LljController.cs
@@ -348,36 +348,87 @@ } } [HttpGet("DownloadFtpFile")] public IActionResult DownloadFtpFile([FromQuery] string itemNo, [FromQuery] string fileName) [HttpGet("PreviewFtpFile")] public IActionResult PreviewFtpFile([FromQuery] string itemNo, [FromQuery] string fileName, [FromQuery] string ftpServer) { // FTP服务器信息 string ftpServer = "ftp://36.26.21.214"; string ftpUser = "hm_ftp"; string ftpPwd = "dell_123"; string ftpPath = $"{ftpServer}/IQC/{itemNo}/{fileName}"; try { var request = (System.Net.FtpWebRequest)System.Net.WebRequest.Create(ftpPath); request.Method = System.Net.WebRequestMethods.Ftp.DownloadFile; request.Credentials = new System.Net.NetworkCredential(ftpUser, ftpPwd); request.UseBinary = true; request.UsePassive = false; using (var response = (System.Net.FtpWebResponse)request.GetResponse()) using (var ftpStream = response.GetResponseStream()) using (var ms = new System.IO.MemoryStream()) // 添加CORS响应头 Response.Headers.Add("Access-Control-Allow-Origin", "*"); Response.Headers.Add("Access-Control-Allow-Methods", "GET, OPTIONS"); Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type"); Response.Headers.Add("Access-Control-Expose-Headers", "Content-Type, Content-Length"); var service = new LljService(); var fileBytes = service.GetFtpFile(itemNo, fileName, ftpServer); if (fileBytes == null || fileBytes.Length == 0) { ftpStream.CopyTo(ms); ms.Position = 0; string contentType = "application/octet-stream"; // 防御性处理,去除fileName中的回车换行和空格 fileName = fileName?.Trim().Replace("\r", "").Replace("\n", ""); return File(ms.ToArray(), contentType, fileName); return NotFound("文件在FTP服务器上不存在"); } var contentType = service.GetContentType(fileName); fileName = fileName?.Trim().Replace("\r", "").Replace("\n", ""); return File(fileBytes, contentType); } catch (Exception ex) { return BadRequest($"FTP下载失败:{ex.Message},ftpPath={ftpPath},fileName={fileName}"); return StatusCode(500, $"预览文件失败:{ex.Message}"); } } [HttpGet("DownloadFtpFile")] public IActionResult DownloadFtpFile([FromQuery] string itemNo, [FromQuery] string fileName, [FromQuery] string ftpServer) { try { // 添加CORS响应头 - 关键配置用于解决跨域问题 Response.Headers.Add("Access-Control-Allow-Origin", "*"); Response.Headers.Add("Access-Control-Allow-Methods", "GET, OPTIONS"); Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Authorization"); Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition, Content-Length, Content-Type"); var service = new LljService(); var fileBytes = service.GetFtpFile(itemNo, fileName, ftpServer); if (fileBytes == null || fileBytes.Length == 0) { return NotFound("文件在FTP服务器上不存在"); } var contentType = service.GetContentType(fileName); fileName = fileName?.Trim().Replace("\r", "").Replace("\n", ""); // 设置正确的Content-Disposition响应头以支持文件下载 var result = File(fileBytes, "application/octet-stream", fileName); // 确保Content-Disposition头正确设置,支持中文文件名 if (!string.IsNullOrEmpty(fileName)) { var encodedFileName = System.Web.HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8); Response.Headers.Add("Content-Disposition", $"attachment; filename*=UTF-8''{encodedFileName}"); } return result; } catch (Exception ex) { return StatusCode(500, $"下载文件失败:{ex.Message}"); } } [HttpOptions("PreviewFtpFile")] [HttpOptions("DownloadFtpFile")] public IActionResult HandleOptions() { // 处理CORS预检请求 Response.Headers.Add("Access-Control-Allow-Origin", "*"); Response.Headers.Add("Access-Control-Allow-Methods", "GET, OPTIONS"); Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Authorization"); Response.Headers.Add("Access-Control-Expose-Headers", "Content-Disposition, Content-Length, Content-Type"); Response.Headers.Add("Access-Control-Max-Age", "86400"); return Ok(); } }