refactor: 统一业务异常处理,标准化结果码和错误响应

1.  新增并完善ResultCode枚举,补充标准HTTP状态码对应的业务状态码
2.  重构BusinessException,新增基于ResultCode的构造函数和ThrowIf扩展方法
3.  替换所有硬编码的HTTP状态码为统一的ResultCode枚举
4.  优化全局异常中间件,根据业务状态码映射对应HTTP状态码并规范化JSON响应
5.  修复OssImageHelper和AutoDotCodeConsumer中的OSS文件处理逻辑
6.  新增用户答题快照实体类
7.  清理废弃的宠物模块迁移脚本
This commit is contained in:
glz
2026-06-29 16:34:26 +08:00
parent 4579fefef9
commit bdaa6a0dc8
35 changed files with 693 additions and 364 deletions

View File

@ -1,6 +1,7 @@
using Microsoft.Extensions.Logging;
using QYZH.InteractiveMagazine.IService;
using QYZH.InteractiveMagazine.Models.Common;
using QYZH.InteractiveMagazine.Models.Dto;
using QYZH.InteractiveMagazine.Models.Dto.Bag;
using QYZH.InteractiveMagazine.Models.Dto.Mall;
using QYZH.InteractiveMagazine.Models.Dto.Points;
@ -187,10 +188,10 @@ public class WxMallService(
userId, input.ProductId, input.Quantity);
if (input.ProductId <= 0)
throw new BusinessException("商品Id无效", 400);
throw new BusinessException("商品Id无效", ResultCode.BAD_REQUEST);
if (input.Quantity <= 0)
throw new BusinessException("兑换数量必须大于0", 400);
throw new BusinessException("兑换数量必须大于0", ResultCode.BAD_REQUEST);
// 查询商品
var product = await exchangeRecordRepository.Context.Queryable<Product>()
@ -198,7 +199,7 @@ public class WxMallService(
.FirstAsync();
if (product == null)
throw new BusinessException("商品不存在或已下架", 404);
throw new BusinessException("商品不存在或已下架", ResultCode.NOT_FOUND);
var totalCost = product.Price * input.Quantity;
@ -404,24 +405,24 @@ public class WxMallService(
logger.LogInformation("使用背包物品UserId: {UserId}, BagItemId: {BagItemId}", userId, input.BagItemId);
if (input.BagItemId <= 0)
throw new BusinessException("背包物品Id无效", 400);
throw new BusinessException("背包物品Id无效", ResultCode.BAD_REQUEST);
var bagItem = await exchangeRecordRepository.Context.Queryable<UserBag>()
.Where(b => b.Id == input.BagItemId && b.UserId == userId && b.Status == (int)UserBagStatusEnum.Available)
.FirstAsync();
if (bagItem == null)
throw new BusinessException("背包物品不存在", 404);
throw new BusinessException("背包物品不存在", ResultCode.NOT_FOUND);
if (bagItem.Quantity <= 0)
throw new BusinessException("物品数量不足", 400);
throw new BusinessException("物品数量不足", ResultCode.BAD_REQUEST);
switch (bagItem.ItemType)
{
case "MakeUpCard":
return await UseMakeUpCardAsync(userId, bagItem, input);
default:
throw new BusinessException($"不支持使用该类型物品: {bagItem.ItemType}", 400);
throw new BusinessException($"不支持使用该类型物品: {bagItem.ItemType}", ResultCode.BAD_REQUEST);
}
}
@ -431,15 +432,15 @@ public class WxMallService(
private async Task<UseItemOutput> UseMakeUpCardAsync(long userId, UserBag bagItem, UseItemInput input)
{
if (string.IsNullOrEmpty(input.TargetDate))
throw new BusinessException("请指定补签日期", 400);
throw new BusinessException("请指定补签日期", ResultCode.BAD_REQUEST);
if (!DateTime.TryParse(input.TargetDate, out var targetDate))
throw new BusinessException("日期格式无效", 400);
throw new BusinessException("日期格式无效", ResultCode.BAD_REQUEST);
targetDate = targetDate.Date;
if (targetDate >= DateTime.Now.Date)
throw new BusinessException("只能补签过去的日期", 400);
throw new BusinessException("只能补签过去的日期", ResultCode.BAD_REQUEST);
// 调用签到服务执行补签(内部会检查并扣减补签卡)
var checkInResult = await checkInService.MakeUpCheckInAsync(userId, targetDate);
@ -467,7 +468,7 @@ public class WxMallService(
.FirstAsync();
if (pet == null)
throw new BusinessException("您还没有宠物", 404);
throw new BusinessException("您还没有宠物", ResultCode.NOT_FOUND);
if (input.SkinId == 0)
{
@ -488,7 +489,7 @@ public class WxMallService(
.FirstAsync();
if (skin == null)
throw new BusinessException("皮肤不存在", 404);
throw new BusinessException("皮肤不存在", ResultCode.NOT_FOUND);
// 校验背包中是否拥有该皮肤(通过 MetaData 中的 SkinId 判断)
var hasSkin = await exchangeRecordRepository.Context.Queryable<UserBag>()
@ -499,7 +500,7 @@ public class WxMallService(
var owned = hasSkin.Any(b => GetSkinIdFromMetaData(b.MetaData) == input.SkinId);
if (!owned)
throw new BusinessException("您尚未拥有该皮肤,请先兑换", 400);
throw new BusinessException("您尚未拥有该皮肤,请先兑换", ResultCode.BAD_REQUEST);
// 换肤
await exchangeRecordRepository.Context.Updateable<UserPet>()