refactor(api): 提取公共API默认配置并修复积分并发问题

1.  新增InteractiveMagazineApiDefaultsExtensions统一注册共享服务,简化WeChatApi和WebApi的Program.cs代码
2.  修复积分增减的并发问题,改用原子更新操作,添加余额校验避免超扣
3.  修复注释乱码问题,将简体中文注释替换为正确文本
4.  新增.editorconfig配置统一代码格式
This commit is contained in:
glz
2026-07-07 18:01:17 +08:00
parent 1d467a5fc4
commit f7f505d109
6 changed files with 139 additions and 154 deletions

View File

@ -73,7 +73,18 @@ public class PointsService(
if (input.Amount <= 0)
throw new BusinessException("增加积分数量必须大于0", ResultCode.BAD_REQUEST);
// 查询用户当前积分
var now = DateTime.Now;
// 原子增加积分,避免并发写回旧余额覆盖新余额
var affectedRows = await Context.Updateable<Users>()
.SetColumns(u => u.Points == u.Points + input.Amount)
.SetColumns(u => u.UpdatedAt == now)
.Where(u => u.Id == input.UserId && !u.IsDeleted)
.ExecuteCommandAsync();
if (affectedRows <= 0)
throw new BusinessException("用户不存在", ResultCode.NOT_FOUND);
var user = await Context.Queryable<Users>()
.Where(u => u.Id == input.UserId && !u.IsDeleted)
.FirstAsync();
@ -81,15 +92,8 @@ public class PointsService(
if (user == null)
throw new BusinessException("用户不存在", ResultCode.NOT_FOUND);
var previousBalance = user.Points;
var newBalance = previousBalance + input.Amount;
// 更新用户积分
await Context.Updateable<Users>()
.SetColumns(u => u.Points == newBalance)
.SetColumns(u => u.UpdatedAt == DateTime.Now)
.Where(u => u.Id == input.UserId && !u.IsDeleted)
.ExecuteCommandAsync();
var newBalance = user.Points;
var previousBalance = newBalance - input.Amount;
// 插入积分流水记录
var record = new PointsRecord
@ -104,9 +108,9 @@ public class PointsService(
Status = (int)PointsRecordStatusEnum.Success,
IsDeleted = false,
CreatedBy = input.OperatorName ?? user.Name ?? input.UserId.ToString(),
CreatedAt = DateTime.Now,
CreatedAt = now,
UpdatedBy = input.OperatorName ?? user.Name ?? input.UserId.ToString(),
UpdatedAt = DateTime.Now
UpdatedAt = now
};
var recordEntity = await InsertReturnEntityAsync(record);
@ -131,7 +135,27 @@ public class PointsService(
if (input.Amount <= 0)
throw new BusinessException("扣除积分数量必须大于0", ResultCode.BAD_REQUEST);
// 查询用户当前积分
var now = DateTime.Now;
// 带余额条件的原子扣减,避免并发扣减时超扣或覆盖余额
var affectedRows = await Context.Updateable<Users>()
.SetColumns(u => u.Points == u.Points - input.Amount)
.SetColumns(u => u.UpdatedAt == now)
.Where(u => u.Id == input.UserId && !u.IsDeleted && u.Points >= input.Amount)
.ExecuteCommandAsync();
if (affectedRows <= 0)
{
var currentUser = await Context.Queryable<Users>()
.Where(u => u.Id == input.UserId && !u.IsDeleted)
.FirstAsync();
if (currentUser == null)
throw new BusinessException("用户不存在", ResultCode.NOT_FOUND);
throw new BusinessException($"积分不足,需要 {input.Amount} 积分,当前余额 {currentUser.Points}", ResultCode.BAD_REQUEST);
}
var user = await Context.Queryable<Users>()
.Where(u => u.Id == input.UserId && !u.IsDeleted)
.FirstAsync();
@ -139,20 +163,8 @@ public class PointsService(
if (user == null)
throw new BusinessException("用户不存在", ResultCode.NOT_FOUND);
var previousBalance = user.Points;
// 余额不足校验
if (previousBalance < input.Amount)
throw new BusinessException($"积分不足,需要 {input.Amount} 积分,当前余额 {previousBalance}", ResultCode.BAD_REQUEST);
var newBalance = previousBalance - input.Amount;
// 更新用户积分
await Context.Updateable<Users>()
.SetColumns(u => u.Points == newBalance)
.SetColumns(u => u.UpdatedAt == DateTime.Now)
.Where(u => u.Id == input.UserId && !u.IsDeleted)
.ExecuteCommandAsync();
var newBalance = user.Points;
var previousBalance = newBalance + input.Amount;
// 插入积分流水记录
var record = new PointsRecord
@ -167,9 +179,9 @@ public class PointsService(
Status = (int)PointsRecordStatusEnum.Success,
IsDeleted = false,
CreatedBy = input.OperatorName ?? user.Name ?? input.UserId.ToString(),
CreatedAt = DateTime.Now,
CreatedAt = now,
UpdatedBy = input.OperatorName ?? user.Name ?? input.UserId.ToString(),
UpdatedAt = DateTime.Now
UpdatedAt = now
};
var recordEntity = await InsertReturnEntityAsync(record);