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
};
}