feat: 新增宠物进化分组接口、OSS图片搬运功能及配置更新

1. 新增皮肤按进化阶段分组的输出DTO
2. 新增宠物相关便捷查询接口并实现对应控制器
3. 新增OSS图片搬运辅助类,实现临时文件迁移逻辑
4. 为商品、宠物相关服务添加OSS图片自动迁移功能
5. 调整微信授权同步逻辑移除异步等待
6. 更新配置文件中的微信密钥和OSS存储信息
7. 注册SDK服务到DI容器
This commit is contained in:
glz
2026-06-09 18:02:26 +08:00
parent badf68a8f8
commit 296d87b245
9 changed files with 421 additions and 10 deletions

View File

@ -0,0 +1,110 @@
using Microsoft.Extensions.Logging;
using QYZH.InteractiveMagazine.Common.Extensions;
using QYZH.InteractiveMagazine.Models.Common;
namespace QYZH.InteractiveMagazine.Infrastructure.OSS;
/// <summary>
/// OSS 图片搬运辅助类
/// 负责将 temp 临时目录下的文件搬运到正式目录
/// </summary>
public class OssImageHelper
{
private readonly OssService _ossService;
private readonly ILogger _logger;
public OssImageHelper(OssService ossService, ILogger logger)
{
_ossService = ossService;
_logger = logger;
}
/// <summary>
/// 判断图片是否在 temp 临时目录
/// </summary>
public static bool IsTempImage(string? imageUrl)
{
if (string.IsNullOrWhiteSpace(imageUrl)) return false;
return imageUrl.Contains("/temp/", StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// 将 temp 目录下的图片搬运到正式目录,返回正式路径
/// 如果图片不在 temp 目录,原样返回
/// </summary>
/// <param name="imageUrl">原始图片 URL可能是完整 URL 或相对路径)</param>
/// <param name="formalFolder">正式目录前缀,如 "product/makeupcard/123" 或 "pet/skin/456"</param>
/// <returns>正式路径(相对路径),搬运失败时抛出异常</returns>
public async Task<string> MoveToFormalAsync(string imageUrl, string formalFolder)
{
if (!IsTempImage(imageUrl))
return imageUrl;
// 提取 OSS 相对路径(去掉域名前缀)
var sourcePath = imageUrl.RemoveDomain();
if (string.IsNullOrWhiteSpace(sourcePath))
{
_logger.LogWarning("图片路径解析失败ImageUrl: {ImageUrl}", imageUrl);
return imageUrl;
}
// URL 解码(处理中文文件名)
sourcePath = Uri.UnescapeDataString(sourcePath);
// 提取文件名
var fileName = Path.GetFileName(sourcePath);
if (string.IsNullOrWhiteSpace(fileName))
{
_logger.LogWarning("无法从路径中提取文件名Path: {Path}", sourcePath);
return imageUrl;
}
// 生成正式路径
var targetPath = $"{formalFolder}/{fileName}";
_logger.LogInformation("开始搬运图片Source: {Source} -> Target: {Target}", sourcePath, targetPath);
try
{
// 拷贝文件到正式目录
var copyResult = _ossService.CopyObject(sourcePath, targetPath);
if (!copyResult)
{
_logger.LogError("OSS 图片拷贝失败Source: {Source}, Target: {Target}", sourcePath, targetPath);
throw new Exception("OSS 图片拷贝失败");
}
// 删除临时文件(失败不影响主流程)
var deleteResult = _ossService.DeleteObject(sourcePath);
if (!deleteResult)
{
_logger.LogWarning("OSS 临时文件删除失败不影响主流程Source: {Source}", sourcePath);
}
_logger.LogInformation("图片搬运成功Target: {Target}", targetPath);
return targetPath;
}
catch (Exception ex) when (ex is not BusinessException)
{
_logger.LogError(ex, "OSS 图片搬运异常Source: {Source}, Target: {Target}", sourcePath, targetPath);
throw new BusinessException("图片搬运失败,请重试", 500);
}
}
/// <summary>
/// 批量搬运 temp 图片到正式目录
/// </summary>
/// <param name="imageUrls">原始图片 URL 列表</param>
/// <param name="formalFolder">正式目录前缀</param>
/// <returns>正式路径列表(顺序与输入一致)</returns>
public async Task<List<string>> MoveBatchToFormalAsync(IEnumerable<string> imageUrls, string formalFolder)
{
var results = new List<string>();
foreach (var url in imageUrls)
{
var formal = await MoveToFormalAsync(url, formalFolder);
results.Add(formal);
}
return results;
}
}