using Fake.Application; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; namespace Oms.Application.Shared; /// /// OMS 上传文件落盘(wwwroot/uploads)。 /// public static class OmsFileUploadHelper { private static readonly HashSet ImageExtensions = new(StringComparer.OrdinalIgnoreCase) { ".jpg", ".jpeg", ".png", ".webp", ".gif", ".bmp" }; private const long MaxImageBytes = 5 * 1024 * 1024; /// /// 保存充值截图,返回以 /uploads 开头的相对访问路径。 /// public static Task SaveRechargeScreenshotAsync(IFormFile? file, IWebHostEnvironment env) => SaveImageAsync(file, env, "recharge", "充值截图"); /// /// 保存仓储 SKU 图片。 /// public static Task SaveWarehouseSkuImageAsync(IFormFile file, IWebHostEnvironment env) => SaveImageAsync(file, env, "sku", "SKU 图片"); /// /// 保存包裹商品图片。 /// public static Task SaveWarehouseParcelImageAsync(IFormFile file, IWebHostEnvironment env) => SaveImageAsync(file, env, "parcel", "包裹商品图片"); private static async Task SaveImageAsync( IFormFile? file, IWebHostEnvironment env, string folder, string label) { if (file == null || file.Length <= 0) { if (folder == "recharge") { return "0"; } throw new BusinessException($"{label}不能为空"); } if (file.Length > MaxImageBytes) { throw new BusinessException($"{label}大小不能超过 5MB"); } var ext = Path.GetExtension(file.FileName); if (string.IsNullOrWhiteSpace(ext) || !ImageExtensions.Contains(ext)) { ext = GuessExtensionFromContentType(file.ContentType) ?? ".jpg"; } if (!ImageExtensions.Contains(ext)) { throw new BusinessException($"{label}仅支持 jpg、png、webp、gif、bmp 格式"); } var webRoot = env.WebRootPath; if (string.IsNullOrWhiteSpace(webRoot)) { webRoot = Path.Combine(env.ContentRootPath, "wwwroot"); } var monthFolder = DateTime.Now.ToString("yyyyMM"); var relativeDir = Path.Combine("uploads", folder, monthFolder); var absoluteDir = Path.Combine(webRoot, relativeDir); Directory.CreateDirectory(absoluteDir); var fileName = $"{Guid.NewGuid():N}{ext.ToLowerInvariant()}"; var absolutePath = Path.Combine(absoluteDir, fileName); await using (var stream = File.Create(absolutePath)) { await file.CopyToAsync(stream); } return $"/uploads/{folder}/{monthFolder}/{fileName}".Replace('\\', '/'); } private static readonly HashSet ExcelExtensions = new(StringComparer.OrdinalIgnoreCase) { ".xlsx", ".xls" }; private const long MaxOrderTemplateBytes = 10 * 1024 * 1024; /// /// 保存下单自定义模板样例文件。 /// public static async Task<(string RelativePath, string FileName)> SaveOrderTemplateSampleAsync( IFormFile file, int customerId, IWebHostEnvironment env) { if (file == null || file.Length <= 0) { throw new BusinessException("上传文件不能为空"); } if (file.Length > MaxOrderTemplateBytes) { throw new BusinessException("模板文件大小不能超过 10MB"); } var ext = Path.GetExtension(file.FileName); if (string.IsNullOrWhiteSpace(ext) || !ExcelExtensions.Contains(ext)) { throw new BusinessException("仅支持 .xlsx / .xls 文件"); } var webRoot = env.WebRootPath; if (string.IsNullOrWhiteSpace(webRoot)) { webRoot = Path.Combine(env.ContentRootPath, "wwwroot"); } var relativeDir = Path.Combine("uploads", "order-templates", customerId.ToString()); var absoluteDir = Path.Combine(webRoot, relativeDir); Directory.CreateDirectory(absoluteDir); var fileName = $"{Guid.NewGuid():N}{ext.ToLowerInvariant()}"; var absolutePath = Path.Combine(absoluteDir, fileName); await using (var stream = File.Create(absolutePath)) { await file.CopyToAsync(stream); } var relativePath = $"/uploads/order-templates/{customerId}/{fileName}".Replace('\\', '/'); return (relativePath, Path.GetFileName(file.FileName)); } public static string ResolveWebRootAbsolutePath(IWebHostEnvironment env, string relativePath) { var webRoot = env.WebRootPath; if (string.IsNullOrWhiteSpace(webRoot)) { webRoot = Path.Combine(env.ContentRootPath, "wwwroot"); } var trimmed = relativePath.TrimStart('/').Replace('/', Path.DirectorySeparatorChar); return Path.Combine(webRoot, trimmed); } private static string? GuessExtensionFromContentType(string? contentType) => contentType?.ToLowerInvariant() switch { "image/jpeg" or "image/jpg" => ".jpg", "image/png" => ".png", "image/webp" => ".webp", "image/gif" => ".gif", "image/bmp" => ".bmp", _ => null }; }