微信小程序上传头像
This commit is contained in:
parent
0e9ba53b76
commit
2a851d1525
@ -600,3 +600,14 @@ public class MyRegistrationDto
|
||||
/// </summary>
|
||||
public string ProjectNames { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新头像输出
|
||||
/// </summary>
|
||||
public class UpdateAvatarOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 头像URL
|
||||
/// </summary>
|
||||
public string AvatarUrl { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using YD_Event.Application.Client.Dtos;
|
||||
using YD_Event.Application.Common;
|
||||
using YD_Event.Core.Entities;
|
||||
using YD_Event.Core.Enum;
|
||||
using SqlSugar;
|
||||
@ -8,6 +9,7 @@ using Microsoft.AspNetCore.Authorization;
|
||||
using System.Security.Claims;
|
||||
using Furion.FriendlyException;
|
||||
using EasyCaching.Core;
|
||||
using SkiaSharp;
|
||||
using ProjectEntity = YD_Event.Core.Entities.Project;
|
||||
|
||||
namespace YD_Event.Application.Client;
|
||||
@ -31,6 +33,7 @@ public class MyController : IDynamicApiController
|
||||
private readonly ISqlSugarRepository<MerchantCertification> _merchantCertificationRepository;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly IEasyCachingProvider _cachingProvider;
|
||||
private readonly FileService _fileService;
|
||||
|
||||
public MyController(
|
||||
ISqlSugarRepository<YD_Event.Core.Entities.AppUser> appUserRepository,
|
||||
@ -44,7 +47,8 @@ public class MyController : IDynamicApiController
|
||||
ISqlSugarRepository<EventInfo> eventRepository,
|
||||
ISqlSugarRepository<MerchantCertification> merchantCertificationRepository,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
IEasyCachingProvider cachingProvider)
|
||||
IEasyCachingProvider cachingProvider,
|
||||
FileService fileService)
|
||||
{
|
||||
_appUserRepository = appUserRepository;
|
||||
_teamRepository = teamRepository;
|
||||
@ -58,6 +62,7 @@ public class MyController : IDynamicApiController
|
||||
_merchantCertificationRepository = merchantCertificationRepository;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_cachingProvider = cachingProvider;
|
||||
_fileService = fileService;
|
||||
}
|
||||
|
||||
private long GetCurrentUserId()
|
||||
@ -658,4 +663,157 @@ public class MyController : IDynamicApiController
|
||||
if (string.IsNullOrEmpty(mobile) || mobile.Length < 7) return mobile;
|
||||
return mobile.Substring(0, 3) + "****" + mobile.Substring(7);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新头像 - 上传图片文件
|
||||
/// </summary>
|
||||
/// <param name="file">头像图片文件</param>
|
||||
/// <returns>更新后的头像信息</returns>
|
||||
[HttpPost("avatar/upload")]
|
||||
[DisplayName("上传头像")]
|
||||
public async Task<UpdateAvatarOutput> UpdateAvatarByFile(IFormFile file)
|
||||
{
|
||||
if (file == null || file.Length == 0)
|
||||
{
|
||||
throw Oops.Bah("请上传头像图片");
|
||||
}
|
||||
|
||||
// 验证文件类型
|
||||
var allowedExtensions = new[] { ".jpg", ".jpeg", ".png", ".gif", ".bmp" };
|
||||
var extension = Path.GetExtension(file.FileName).ToLower();
|
||||
if (!allowedExtensions.Contains(extension))
|
||||
{
|
||||
throw Oops.Bah("仅支持 JPG、JPEG、PNG、GIF、BMP 格式的图片");
|
||||
}
|
||||
|
||||
// 验证文件大小 (最大 5MB)
|
||||
if (file.Length > 5 * 1024 * 1024)
|
||||
{
|
||||
throw Oops.Bah("图片大小不能超过 5MB");
|
||||
}
|
||||
|
||||
// 处理图片
|
||||
using var processedStream = await ProcessAvatarImage(file.OpenReadStream());
|
||||
|
||||
// 上传处理后的图片
|
||||
var now = DateTime.Now;
|
||||
var fileName = $"avatar/{now.Year}/{now.Month:D2}/{now.Day:D2}/{Yitter.IdGenerator.YitIdHelper.NextId()}.jpg";
|
||||
var avatarUrl = await _fileService.UploadFileStreamAsync(fileName, processedStream);
|
||||
|
||||
// 更新用户头像
|
||||
var userId = GetCurrentUserId();
|
||||
var user = await _appUserRepository.GetFirstAsync(u => u.Id == userId);
|
||||
if (user == null)
|
||||
{
|
||||
throw Oops.Bah("用户信息不存在");
|
||||
}
|
||||
|
||||
user.Avatar = avatarUrl;
|
||||
user.UpdatedTime = DateTime.Now;
|
||||
await _appUserRepository.UpdateAsync(user);
|
||||
|
||||
return new UpdateAvatarOutput
|
||||
{
|
||||
AvatarUrl = avatarUrl
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新头像 - 使用图片URL
|
||||
/// </summary>
|
||||
/// <param name="avatarUrl">头像图片URL</param>
|
||||
/// <returns>更新后的头像信息</returns>
|
||||
[HttpPost("avatar/url")]
|
||||
[DisplayName("更新头像URL")]
|
||||
public async Task<UpdateAvatarOutput> UpdateAvatarByUrl([FromBody] string avatarUrl)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(avatarUrl))
|
||||
{
|
||||
throw Oops.Bah("头像URL不能为空");
|
||||
}
|
||||
|
||||
// 验证URL格式
|
||||
if (!Uri.TryCreate(avatarUrl, UriKind.Absolute, out _))
|
||||
{
|
||||
throw Oops.Bah("头像URL格式不正确");
|
||||
}
|
||||
|
||||
// 更新用户头像
|
||||
var userId = GetCurrentUserId();
|
||||
var user = await _appUserRepository.GetFirstAsync(u => u.Id == userId);
|
||||
if (user == null)
|
||||
{
|
||||
throw Oops.Bah("用户信息不存在");
|
||||
}
|
||||
|
||||
user.Avatar = avatarUrl;
|
||||
user.UpdatedTime = DateTime.Now;
|
||||
await _appUserRepository.UpdateAsync(user);
|
||||
|
||||
return new UpdateAvatarOutput
|
||||
{
|
||||
AvatarUrl = avatarUrl
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理头像图片 - 压缩和格式转换
|
||||
/// </summary>
|
||||
/// <param name="inputStream">原始图片流</param>
|
||||
/// <returns>处理后的图片流</returns>
|
||||
private async Task<Stream> ProcessAvatarImage(Stream inputStream)
|
||||
{
|
||||
// 将流复制到内存流,以便可以多次读取
|
||||
var memoryStream = new MemoryStream();
|
||||
await inputStream.CopyToAsync(memoryStream);
|
||||
memoryStream.Position = 0;
|
||||
|
||||
// 使用 SkiaSharp 处理图片
|
||||
using var originalBitmap = SKBitmap.Decode(memoryStream);
|
||||
if (originalBitmap == null)
|
||||
{
|
||||
throw Oops.Bah("图片解码失败,请检查图片格式");
|
||||
}
|
||||
|
||||
// 计算缩放后的尺寸(最大 200x200)
|
||||
const int maxSize = 200;
|
||||
int width = originalBitmap.Width;
|
||||
int height = originalBitmap.Height;
|
||||
|
||||
if (width > maxSize || height > maxSize)
|
||||
{
|
||||
if (width > height)
|
||||
{
|
||||
height = (int)(height * (double)maxSize / width);
|
||||
width = maxSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
width = (int)(width * (double)maxSize / height);
|
||||
height = maxSize;
|
||||
}
|
||||
}
|
||||
|
||||
// 创建缩放后的图片
|
||||
using var scaledBitmap = originalBitmap.Resize(new SKImageInfo(width, height), SKFilterQuality.High);
|
||||
|
||||
// 裁剪为正方形(从中心裁剪)
|
||||
int cropSize = Math.Min(width, height);
|
||||
int cropX = (width - cropSize) / 2;
|
||||
int cropY = (height - cropSize) / 2;
|
||||
|
||||
using var croppedBitmap = new SKBitmap(cropSize, cropSize);
|
||||
using var canvas = new SKCanvas(croppedBitmap);
|
||||
canvas.Clear(SKColors.Transparent);
|
||||
canvas.DrawBitmap(scaledBitmap, new SKRect(cropX, cropY, cropX + cropSize, cropY + cropSize), new SKRect(0, 0, cropSize, cropSize));
|
||||
|
||||
// 转换为 JPG 格式并压缩
|
||||
var outputStream = new MemoryStream();
|
||||
using var image = SKImage.FromBitmap(croppedBitmap);
|
||||
using var data = image.Encode(SKEncodedImageFormat.Jpeg, 80); // 80% 质量
|
||||
data.SaveTo(outputStream);
|
||||
outputStream.Position = 0;
|
||||
|
||||
return outputStream;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user