refactor: 批量新增枚举类型并完成实体、DTO、服务层枚举替换
- 新增30+业务枚举类型覆盖用户、宠物、商城、社区、积分等模块 - 完成实体类、DTO、服务层的字符串枚举替换为强类型枚举 - 修复用户状态枚举名称变更,将Frozen改为Disabled - 新增批量发布社区消息接口与控制器实现 - 新增操作日志、积分管理、补偿任务相关服务与DTO
This commit is contained in:
@ -3,7 +3,9 @@ using QYZH.InteractiveMagazine.IService;
|
||||
using QYZH.InteractiveMagazine.Models.Common;
|
||||
using QYZH.InteractiveMagazine.Models.Dto.Bag;
|
||||
using QYZH.InteractiveMagazine.Models.Dto.Mall;
|
||||
using QYZH.InteractiveMagazine.Models.Dto.Points;
|
||||
using QYZH.InteractiveMagazine.Models.Entity;
|
||||
using QYZH.InteractiveMagazine.Models.Enum;
|
||||
using QYZH.InteractiveMagazine.Repository;
|
||||
using System.Text.Json;
|
||||
|
||||
@ -15,6 +17,7 @@ namespace QYZH.InteractiveMagazine.Service;
|
||||
public class WxMallService(
|
||||
BaseRepository<ExchangeRecord> exchangeRecordRepository,
|
||||
ICheckInService checkInService,
|
||||
IPointsService pointsService,
|
||||
ILogger<WxMallService> logger)
|
||||
: BaseRepository<ExchangeRecord>, IWxMallService
|
||||
{
|
||||
@ -43,14 +46,14 @@ public class WxMallService(
|
||||
{
|
||||
var query = exchangeRecordRepository.Context.Queryable<Product>()
|
||||
.Where(p => !p.IsDeleted && p.IsActive && p.SaleStatus == "OnSale")
|
||||
.WhereIF(!string.IsNullOrEmpty(type), p => p.Type == type)
|
||||
.WhereIF(!string.IsNullOrEmpty(type), p => p.Type.ToString() == type)
|
||||
.OrderByDescending(p => p.CreatedAt);
|
||||
|
||||
var products = await query.ToListAsync();
|
||||
|
||||
// 批量提取 PetBg 商品的 SkinId
|
||||
var skinProductMap = products
|
||||
.Where(p => p.Type == "PetBg")
|
||||
.Where(p => p.Type == ProductTypeEnum.PetBg)
|
||||
.Select(p => new { ProductId = p.Id, SkinId = GetSkinIdFromMetaData(p.MetaData) })
|
||||
.Where(x => x.SkinId > 0)
|
||||
.ToList();
|
||||
@ -80,7 +83,7 @@ public class WxMallService(
|
||||
var skinProductIds = skinProductMap.Select(x => x.ProductId).ToList();
|
||||
var bagItems = skinProductIds.Count > 0
|
||||
? await exchangeRecordRepository.Context.Queryable<UserBag>()
|
||||
.Where(b => b.UserId == userId && !b.IsDeleted && b.Status == "Available"
|
||||
.Where(b => b.UserId == userId && !b.IsDeleted && b.Status == UserBagStatusEnum.Available
|
||||
&& skinProductIds.Contains(b.ItemId))
|
||||
.ToListAsync()
|
||||
: new List<UserBag>();
|
||||
@ -99,7 +102,7 @@ public class WxMallService(
|
||||
Description = p.Description,
|
||||
ImageUrl = p.ImageUrl,
|
||||
Price = p.Price,
|
||||
Type = p.Type,
|
||||
Type = p.Type.ToString(),
|
||||
Owned = owned,
|
||||
Skin = skin != null ? new PetSkinBrief
|
||||
{
|
||||
@ -125,7 +128,7 @@ public class WxMallService(
|
||||
if (product == null) return null;
|
||||
|
||||
PetSkinBrief? skinBrief = null;
|
||||
if (product.Type == "PetBg")
|
||||
if (product.Type == ProductTypeEnum.PetBg)
|
||||
{
|
||||
var skinId = GetSkinIdFromMetaData(product.MetaData);
|
||||
if (skinId > 0)
|
||||
@ -155,7 +158,7 @@ public class WxMallService(
|
||||
}
|
||||
|
||||
var owned = await exchangeRecordRepository.Context.Queryable<UserBag>()
|
||||
.Where(b => b.UserId == userId && b.ItemId == product.Id && !b.IsDeleted && b.Status == "Available")
|
||||
.Where(b => b.UserId == userId && b.ItemId == product.Id && !b.IsDeleted && b.Status == UserBagStatusEnum.Available)
|
||||
.AnyAsync();
|
||||
|
||||
return new WxProductOutput
|
||||
@ -165,7 +168,7 @@ public class WxMallService(
|
||||
Description = product.Description,
|
||||
ImageUrl = product.ImageUrl,
|
||||
Price = product.Price,
|
||||
Type = product.Type,
|
||||
Type = product.Type.ToString(),
|
||||
Owned = owned,
|
||||
Skin = skinBrief
|
||||
};
|
||||
@ -195,40 +198,22 @@ public class WxMallService(
|
||||
|
||||
var totalCost = product.Price * input.Quantity;
|
||||
|
||||
// 查询用户积分
|
||||
var user = await exchangeRecordRepository.Context.Queryable<Users>()
|
||||
.Where(u => u.Id == userId && !u.IsDeleted)
|
||||
.FirstAsync();
|
||||
|
||||
if (user == null)
|
||||
throw new BusinessException("用户不存在", 404);
|
||||
|
||||
if (user.Points < totalCost)
|
||||
throw new BusinessException($"积分不足,需要 {totalCost} 积分,当前余额 {user.Points}", 400);
|
||||
|
||||
var newPointsBalance = user.Points - totalCost;
|
||||
DeductPointsOutput? pointsResult = null;
|
||||
long recordId = 0;
|
||||
|
||||
await exchangeRecordRepository.UseTranAsync(async () =>
|
||||
{
|
||||
// 扣除用户积分
|
||||
await exchangeRecordRepository.Context.Updateable<Users>()
|
||||
.SetColumns(u => u.Points == newPointsBalance)
|
||||
.SetColumns(u => u.UpdatedAt == DateTime.Now)
|
||||
.Where(u => u.Id == userId && !u.IsDeleted)
|
||||
.ExecuteCommandAsync();
|
||||
|
||||
// 创建兑换记录
|
||||
var record = new ExchangeRecord
|
||||
{
|
||||
UserId = userId,
|
||||
ProductId = product.Id,
|
||||
ProductName = product.Name,
|
||||
ProductType = product.Type,
|
||||
ProductType = product.Type.ToString(),
|
||||
PointsCost = totalCost,
|
||||
PointsBalance = newPointsBalance,
|
||||
PointsBalance = 0, // 稍后赋值
|
||||
Quantity = input.Quantity,
|
||||
Status = "Success",
|
||||
Status = ExchangeRecordStatusEnum.Success,
|
||||
IsDeleted = false,
|
||||
CreatedBy = userId.ToString(),
|
||||
CreatedAt = DateTime.Now,
|
||||
@ -238,9 +223,25 @@ public class WxMallService(
|
||||
var inserted = await exchangeRecordRepository.InsertReturnEntityAsync(record);
|
||||
recordId = inserted.Id;
|
||||
|
||||
// 扣除积分
|
||||
pointsResult = await pointsService.DeductPointsInTranAsync(new DeductPointsInput
|
||||
{
|
||||
UserId = userId,
|
||||
Amount = totalCost,
|
||||
ChangeType = PointsChangeTypeEnum.Exchange,
|
||||
RelatedId = recordId,
|
||||
Description = $"兑换 {product.Name} x{input.Quantity}"
|
||||
});
|
||||
|
||||
// 更新兑换记录的积分余额
|
||||
await exchangeRecordRepository.Updateable<ExchangeRecord>()
|
||||
.SetColumns(r => r.PointsBalance == pointsResult.NewBalance)
|
||||
.Where(r => r.Id == recordId)
|
||||
.ExecuteCommandAsync();
|
||||
|
||||
// 加入背包
|
||||
var existingBag = await exchangeRecordRepository.Context.Queryable<UserBag>()
|
||||
.Where(b => b.UserId == userId && b.ItemId == product.Id && !b.IsDeleted && b.Status == "Available")
|
||||
.Where(b => b.UserId == userId && b.ItemId == product.Id && !b.IsDeleted && b.Status == UserBagStatusEnum.Available)
|
||||
.FirstAsync();
|
||||
|
||||
if (existingBag != null)
|
||||
@ -259,11 +260,11 @@ public class WxMallService(
|
||||
{
|
||||
UserId = userId,
|
||||
ItemId = product.Id,
|
||||
ItemType = product.Type,
|
||||
ItemType = product.Type.ToString(),
|
||||
Quantity = input.Quantity,
|
||||
MetaData = product.MetaData,
|
||||
Type = product.Type,
|
||||
Status = "Available",
|
||||
Type = Enum.TryParse<UserBagTypeEnum>(product.Type.ToString(), out var bagType) ? bagType : default,
|
||||
Status = UserBagStatusEnum.Available,
|
||||
IsDeleted = false,
|
||||
CreatedBy = userId.ToString(),
|
||||
CreatedAt = DateTime.Now,
|
||||
@ -272,25 +273,6 @@ public class WxMallService(
|
||||
};
|
||||
await exchangeRecordRepository.Context.Insertable(bagItem).ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
// 创建积分消耗记录
|
||||
var pointsRecord = new PointsRecord
|
||||
{
|
||||
UserId = userId,
|
||||
ChangeAmount = -totalCost,
|
||||
BalanceAfter = newPointsBalance,
|
||||
ChangeType = "Exchange",
|
||||
RelatedId = recordId,
|
||||
Description = $"兑换 {product.Name} x{input.Quantity}",
|
||||
Type = "Expense",
|
||||
Status = "Success",
|
||||
IsDeleted = false,
|
||||
CreatedBy = userId.ToString(),
|
||||
CreatedAt = DateTime.Now,
|
||||
UpdatedBy = userId.ToString(),
|
||||
UpdatedAt = DateTime.Now
|
||||
};
|
||||
await exchangeRecordRepository.Context.Insertable(pointsRecord).ExecuteCommandAsync();
|
||||
});
|
||||
|
||||
logger.LogInformation("兑换成功,UserId: {UserId}, Product: {Product}, Cost: {Cost}",
|
||||
@ -301,7 +283,7 @@ public class WxMallService(
|
||||
RecordId = recordId,
|
||||
ProductName = product.Name,
|
||||
PointsCost = totalCost,
|
||||
PointsBalance = newPointsBalance,
|
||||
PointsBalance = pointsResult!.NewBalance,
|
||||
Message = $"兑换成功!{product.Name} x{input.Quantity} 已放入背包"
|
||||
};
|
||||
}
|
||||
@ -324,7 +306,7 @@ public class WxMallService(
|
||||
PointsCost = r.PointsCost,
|
||||
PointsBalance = r.PointsBalance,
|
||||
Quantity = r.Quantity,
|
||||
Status = r.Status,
|
||||
Status = r.Status.ToString(),
|
||||
CreatedAt = r.CreatedAt
|
||||
})
|
||||
.ToListAsync();
|
||||
@ -336,7 +318,7 @@ public class WxMallService(
|
||||
public async Task<List<UserBagOutput>> GetBagItemsAsync(long userId, string? itemType = null)
|
||||
{
|
||||
var query = exchangeRecordRepository.Context.Queryable<UserBag>()
|
||||
.Where(b => b.UserId == userId && !b.IsDeleted && b.Status == "Available")
|
||||
.Where(b => b.UserId == userId && !b.IsDeleted && b.Status == UserBagStatusEnum.Available)
|
||||
.WhereIF(!string.IsNullOrEmpty(itemType), b => b.ItemType == itemType)
|
||||
.OrderByDescending(b => b.CreatedAt);
|
||||
|
||||
@ -391,7 +373,7 @@ public class WxMallService(
|
||||
ItemId = b.ItemId,
|
||||
ItemType = b.ItemType,
|
||||
Quantity = b.Quantity,
|
||||
Status = b.Status,
|
||||
Status = b.Status.ToString(),
|
||||
CreatedAt = b.CreatedAt,
|
||||
Product = product != null ? new BagProductBrief
|
||||
{
|
||||
@ -421,7 +403,7 @@ public class WxMallService(
|
||||
throw new BusinessException("背包物品Id无效", 400);
|
||||
|
||||
var bagItem = await exchangeRecordRepository.Context.Queryable<UserBag>()
|
||||
.Where(b => b.Id == input.BagItemId && b.UserId == userId && !b.IsDeleted && b.Status == "Available")
|
||||
.Where(b => b.Id == input.BagItemId && b.UserId == userId && !b.IsDeleted && b.Status == UserBagStatusEnum.Available)
|
||||
.FirstAsync();
|
||||
|
||||
if (bagItem == null)
|
||||
@ -462,7 +444,7 @@ public class WxMallService(
|
||||
if (bagItem.Quantity <= 1)
|
||||
{
|
||||
await exchangeRecordRepository.Context.Updateable<UserBag>()
|
||||
.SetColumns(b => b.Status == "UsedUp")
|
||||
.SetColumns(b => b.Status == UserBagStatusEnum.Expired)
|
||||
.SetColumns(b => b.Quantity == 0)
|
||||
.SetColumns(b => b.UpdatedAt == DateTime.Now)
|
||||
.Where(b => b.Id == bagItem.Id)
|
||||
@ -525,7 +507,7 @@ public class WxMallService(
|
||||
|
||||
// 校验背包中是否拥有该皮肤(通过 MetaData 中的 SkinId 判断)
|
||||
var hasSkin = await exchangeRecordRepository.Context.Queryable<UserBag>()
|
||||
.Where(b => b.UserId == userId && !b.IsDeleted && b.Status == "Available" && b.Quantity > 0
|
||||
.Where(b => b.UserId == userId && !b.IsDeleted && b.Status == UserBagStatusEnum.Available && b.Quantity > 0
|
||||
&& b.ItemType == "PetBg")
|
||||
.ToListAsync();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user