245 lines
7.3 KiB
C#
245 lines
7.3 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
|
|
namespace DRS9.Dashboard.Server.Controllers;
|
|
|
|
[ApiController]
|
|
[Route("api/admin/[controller]")]
|
|
// [Authorize] - 暂时禁用认证以便测试
|
|
public class UploadController : ControllerBase
|
|
{
|
|
private readonly IWebHostEnvironment _environment;
|
|
private readonly ILogger<UploadController> _logger;
|
|
|
|
// 允许的图片扩展名
|
|
private static readonly string[] ImageExtensions = { ".png", ".jpg", ".jpeg", ".gif", ".bmp", ".svg", ".webp" };
|
|
// 允许的视频扩展名
|
|
private static readonly string[] VideoExtensions = { ".mp4", ".webm", ".ogg", ".mov", ".avi", ".mkv" };
|
|
// 最大文件大小 (50MB)
|
|
private const long MaxFileSize = 50 * 1024 * 1024;
|
|
|
|
public UploadController(IWebHostEnvironment environment, ILogger<UploadController> logger)
|
|
{
|
|
_environment = environment;
|
|
_logger = logger;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 上传文件(图片或视频)
|
|
/// </summary>
|
|
[HttpPost]
|
|
public async Task<ActionResult<object>> UploadFile(IFormFile file)
|
|
{
|
|
if (file == null || file.Length == 0)
|
|
{
|
|
return BadRequest(new { success = false, message = "请选择文件" });
|
|
}
|
|
|
|
// 检查文件大小
|
|
if (file.Length > MaxFileSize)
|
|
{
|
|
return BadRequest(new { success = false, message = $"文件大小不能超过 {MaxFileSize / 1024 / 1024}MB" });
|
|
}
|
|
|
|
var extension = Path.GetExtension(file.FileName).ToLowerInvariant();
|
|
|
|
// 确定文件类型
|
|
string itemType;
|
|
string subFolder;
|
|
|
|
if (ImageExtensions.Contains(extension))
|
|
{
|
|
itemType = "Image";
|
|
subFolder = "images";
|
|
}
|
|
else if (VideoExtensions.Contains(extension))
|
|
{
|
|
itemType = "Video";
|
|
subFolder = "videos";
|
|
}
|
|
else
|
|
{
|
|
return BadRequest(new { success = false, message = "不支持的文件类型,请上传图片或视频" });
|
|
}
|
|
|
|
try
|
|
{
|
|
// 创建上传目录
|
|
var uploadsFolder = Path.Combine(_environment.WebRootPath, "uploads", subFolder);
|
|
if (!Directory.Exists(uploadsFolder))
|
|
{
|
|
Directory.CreateDirectory(uploadsFolder);
|
|
}
|
|
|
|
// 生成唯一文件名
|
|
var uniqueFileName = $"{Guid.NewGuid()}{extension}";
|
|
var filePath = Path.Combine(uploadsFolder, uniqueFileName);
|
|
|
|
// 保存文件
|
|
using (var stream = new FileStream(filePath, FileMode.Create))
|
|
{
|
|
await file.CopyToAsync(stream);
|
|
}
|
|
|
|
// 返回文件 URL
|
|
var fileUrl = $"/uploads/{subFolder}/{uniqueFileName}";
|
|
|
|
_logger.LogInformation("文件上传成功: {FileName} -> {Url}", file.FileName, fileUrl);
|
|
|
|
return Ok(new
|
|
{
|
|
success = true,
|
|
message = "上传成功",
|
|
url = fileUrl,
|
|
itemType = itemType,
|
|
fileName = file.FileName
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "文件上传失败");
|
|
return StatusCode(500, new { success = false, message = $"上传失败: {ex.Message}" });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 批量上传文件
|
|
/// </summary>
|
|
[HttpPost("batch")]
|
|
public async Task<ActionResult<object>> UploadFiles(List<IFormFile> files)
|
|
{
|
|
if (files == null || files.Count == 0)
|
|
{
|
|
return BadRequest(new { success = false, message = "请选择文件" });
|
|
}
|
|
|
|
var results = new List<object>();
|
|
var successCount = 0;
|
|
var failCount = 0;
|
|
|
|
foreach (var file in files)
|
|
{
|
|
var result = await UploadSingleFile(file);
|
|
if (result.success)
|
|
{
|
|
successCount++;
|
|
}
|
|
else
|
|
{
|
|
failCount++;
|
|
}
|
|
results.Add(new
|
|
{
|
|
fileName = file.FileName,
|
|
success = result.success,
|
|
message = result.message,
|
|
url = result.url,
|
|
itemType = result.itemType
|
|
});
|
|
}
|
|
|
|
return Ok(new
|
|
{
|
|
success = true,
|
|
message = $"上传完成: {successCount} 个成功, {failCount} 个失败",
|
|
results = results
|
|
});
|
|
}
|
|
|
|
private async Task<(bool success, string message, string? url, string? itemType)> UploadSingleFile(IFormFile file)
|
|
{
|
|
if (file == null || file.Length == 0)
|
|
{
|
|
return (false, "请选择文件", null, null);
|
|
}
|
|
|
|
if (file.Length > MaxFileSize)
|
|
{
|
|
return (false, $"文件大小不能超过 {MaxFileSize / 1024 / 1024}MB", null, null);
|
|
}
|
|
|
|
var extension = Path.GetExtension(file.FileName).ToLowerInvariant();
|
|
|
|
string itemType;
|
|
string subFolder;
|
|
|
|
if (ImageExtensions.Contains(extension))
|
|
{
|
|
itemType = "Image";
|
|
subFolder = "images";
|
|
}
|
|
else if (VideoExtensions.Contains(extension))
|
|
{
|
|
itemType = "Video";
|
|
subFolder = "videos";
|
|
}
|
|
else
|
|
{
|
|
return (false, "不支持的文件类型", null, null);
|
|
}
|
|
|
|
try
|
|
{
|
|
var uploadsFolder = Path.Combine(_environment.WebRootPath, "uploads", subFolder);
|
|
if (!Directory.Exists(uploadsFolder))
|
|
{
|
|
Directory.CreateDirectory(uploadsFolder);
|
|
}
|
|
|
|
var uniqueFileName = $"{Guid.NewGuid()}{extension}";
|
|
var filePath = Path.Combine(uploadsFolder, uniqueFileName);
|
|
|
|
using (var stream = new FileStream(filePath, FileMode.Create))
|
|
{
|
|
await file.CopyToAsync(stream);
|
|
}
|
|
|
|
var fileUrl = $"/uploads/{subFolder}/{uniqueFileName}";
|
|
return (true, "上传成功", fileUrl, itemType);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "文件上传失败: {FileName}", file.FileName);
|
|
return (false, $"上传失败: {ex.Message}", null, null);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 删除文件
|
|
/// </summary>
|
|
[HttpDelete]
|
|
public ActionResult DeleteFile([FromBody] FileDeleteRequest request)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(request.Url))
|
|
{
|
|
return BadRequest(new { success = false, message = "请提供文件 URL" });
|
|
}
|
|
|
|
try
|
|
{
|
|
// 从 URL 中提取文件路径
|
|
var filePath = Path.Combine(_environment.WebRootPath, request.Url.TrimStart('/'));
|
|
|
|
if (System.IO.File.Exists(filePath))
|
|
{
|
|
System.IO.File.Delete(filePath);
|
|
_logger.LogInformation("文件删除成功: {Url}", request.Url);
|
|
return Ok(new { success = true, message = "删除成功" });
|
|
}
|
|
else
|
|
{
|
|
return NotFound(new { success = false, message = "文件不存在" });
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "文件删除失败: {Url}", request.Url);
|
|
return StatusCode(500, new { success = false, message = $"删除失败: {ex.Message}" });
|
|
}
|
|
}
|
|
}
|
|
|
|
public class FileDeleteRequest
|
|
{
|
|
public string Url { get; set; } = string.Empty;
|
|
}
|