refactor: 重构勋章模块,拆分规则独立管理,优化期刊绑定逻辑
1. 新增MedalRule实体类,将勋章条件拆分独立为规则管理 2. 重构Medal相关服务和DTO,支持勋章规则的增删改查 3. 简化Journal绑定逻辑,移除冗余的实例化期刊校验和字段 4. 重命名部分实体类,统一命名前缀 5. 为勋章相关操作添加事务管理,优化异常处理逻辑
This commit is contained in:
@ -15,7 +15,7 @@ public class MedalService(BaseRepository<Medal> medalRepository, ILogger<MedalSe
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 创建勋章
|
||||
/// 创建勋章(含规则,事务)
|
||||
/// </summary>
|
||||
public async Task<MedalOutput> CreateAsync(MedalInput input)
|
||||
{
|
||||
@ -26,28 +26,16 @@ public class MedalService(BaseRepository<Medal> medalRepository, ILogger<MedalSe
|
||||
throw new BusinessException("勋章名称不能为空", 400);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input.ConditionType))
|
||||
{
|
||||
throw new BusinessException("条件类型不能为空", 400);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input.Type))
|
||||
{
|
||||
throw new BusinessException("勋章类型不能为空", 400);
|
||||
}
|
||||
|
||||
if (input.ConditionValue < 0)
|
||||
{
|
||||
throw new BusinessException("条件阈值不能为负数", 400);
|
||||
}
|
||||
|
||||
var medal = new Medal
|
||||
{
|
||||
Name = input.Name.Trim(),
|
||||
Description = input.Description,
|
||||
ImageUrl = input.ImageUrl,
|
||||
ConditionType = input.ConditionType,
|
||||
ConditionValue = input.ConditionValue,
|
||||
SortOrder = input.SortOrder,
|
||||
Type = input.Type,
|
||||
JournalId = input.JournalId,
|
||||
@ -58,35 +46,40 @@ public class MedalService(BaseRepository<Medal> medalRepository, ILogger<MedalSe
|
||||
IsDeleted = false
|
||||
};
|
||||
|
||||
var result = await medalRepository.InsertAsync(medal);
|
||||
if (!result)
|
||||
try
|
||||
{
|
||||
logger.LogError("勋章创建失败,勋章名称: {Name}", input.Name);
|
||||
await UseTranAsync(async () =>
|
||||
{
|
||||
var result = await medalRepository.InsertAsync(medal);
|
||||
if (!result)
|
||||
{
|
||||
throw new BusinessException("创建勋章失败", 500);
|
||||
}
|
||||
|
||||
if (input.Rules != null && input.Rules.Count > 0)
|
||||
{
|
||||
await InsertRulesAsync(medal.Id, input.Rules);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (BusinessException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "勋章创建事务失败,勋章名称: {Name}", input.Name);
|
||||
throw new BusinessException("创建勋章失败", 500);
|
||||
}
|
||||
|
||||
logger.LogInformation("勋章创建成功,勋章名称: {Name}, ID: {Id}", input.Name, medal.Id);
|
||||
|
||||
return new MedalOutput
|
||||
{
|
||||
Id = medal.Id,
|
||||
Name = medal.Name,
|
||||
Description = medal.Description,
|
||||
ImageUrl = medal.ImageUrl,
|
||||
ConditionType = medal.ConditionType,
|
||||
ConditionValue = medal.ConditionValue,
|
||||
SortOrder = medal.SortOrder,
|
||||
Type = medal.Type,
|
||||
JournalId = medal.JournalId,
|
||||
CreatedBy = medal.CreatedBy,
|
||||
CreatedAt = medal.CreatedAt,
|
||||
UpdatedBy = medal.UpdatedBy,
|
||||
UpdatedAt = medal.UpdatedAt
|
||||
};
|
||||
var rules = await GetRulesByMedalIdAsync(medal.Id);
|
||||
return BuildMedalOutput(medal, rules);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新勋章
|
||||
/// 更新勋章(含规则,事务)
|
||||
/// </summary>
|
||||
public async Task<MedalOutput> UpdateAsync(long id, MedalInput input)
|
||||
{
|
||||
@ -104,61 +97,60 @@ public class MedalService(BaseRepository<Medal> medalRepository, ILogger<MedalSe
|
||||
throw new BusinessException("勋章名称不能为空", 400);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input.ConditionType))
|
||||
{
|
||||
throw new BusinessException("条件类型不能为空", 400);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input.Type))
|
||||
{
|
||||
throw new BusinessException("勋章类型不能为空", 400);
|
||||
}
|
||||
|
||||
if (input.ConditionValue < 0)
|
||||
{
|
||||
throw new BusinessException("条件阈值不能为负数", 400);
|
||||
}
|
||||
|
||||
medal.Name = input.Name.Trim();
|
||||
medal.Description = input.Description;
|
||||
medal.ImageUrl = input.ImageUrl;
|
||||
medal.ConditionType = input.ConditionType;
|
||||
medal.ConditionValue = input.ConditionValue;
|
||||
medal.SortOrder = input.SortOrder;
|
||||
medal.Type = input.Type;
|
||||
medal.JournalId = input.JournalId;
|
||||
medal.UpdatedBy = "System";
|
||||
medal.UpdatedAt = DateTime.Now;
|
||||
|
||||
var result = await medalRepository.UpdateAsync(medal);
|
||||
if (!result)
|
||||
try
|
||||
{
|
||||
logger.LogError("勋章更新失败,ID: {Id}", id);
|
||||
await UseTranAsync(async () =>
|
||||
{
|
||||
var result = await medalRepository.UpdateAsync(medal);
|
||||
if (!result)
|
||||
{
|
||||
throw new BusinessException("更新勋章失败", 500);
|
||||
}
|
||||
|
||||
// 删除旧规则,重新插入新规则
|
||||
await Context.Updateable<MedalRule>()
|
||||
.SetColumns(r => new MedalRule { IsDeleted = true, UpdatedBy = "System", UpdatedAt = DateTime.Now })
|
||||
.Where(r => r.MedalId == medal.Id)
|
||||
.ExecuteCommandAsync();
|
||||
|
||||
if (input.Rules != null && input.Rules.Count > 0)
|
||||
{
|
||||
await InsertRulesAsync(medal.Id, input.Rules);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (BusinessException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "勋章更新事务失败,ID: {Id}", id);
|
||||
throw new BusinessException("更新勋章失败", 500);
|
||||
}
|
||||
|
||||
logger.LogInformation("勋章更新成功,ID: {Id}", id);
|
||||
|
||||
return new MedalOutput
|
||||
{
|
||||
Id = medal.Id,
|
||||
Name = medal.Name,
|
||||
Description = medal.Description,
|
||||
ImageUrl = medal.ImageUrl,
|
||||
ConditionType = medal.ConditionType,
|
||||
ConditionValue = medal.ConditionValue,
|
||||
SortOrder = medal.SortOrder,
|
||||
Type = medal.Type,
|
||||
JournalId = medal.JournalId,
|
||||
CreatedBy = medal.CreatedBy,
|
||||
CreatedAt = medal.CreatedAt,
|
||||
UpdatedBy = medal.UpdatedBy,
|
||||
UpdatedAt = medal.UpdatedAt
|
||||
};
|
||||
var rules = await GetRulesByMedalIdAsync(medal.Id);
|
||||
return BuildMedalOutput(medal, rules);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除勋章(软删除)
|
||||
/// 删除勋章(软删除,含规则)
|
||||
/// </summary>
|
||||
public async Task DeleteAsync(long id)
|
||||
{
|
||||
@ -171,10 +163,30 @@ public class MedalService(BaseRepository<Medal> medalRepository, ILogger<MedalSe
|
||||
throw new BusinessException("勋章不存在", 404);
|
||||
}
|
||||
|
||||
var result = await medalRepository.DeleteByIdAsync(id);
|
||||
if (!result)
|
||||
try
|
||||
{
|
||||
logger.LogError("勋章删除失败,ID: {Id}", id);
|
||||
await UseTranAsync(async () =>
|
||||
{
|
||||
var result = await medalRepository.DeleteByIdAsync(id);
|
||||
if (!result)
|
||||
{
|
||||
throw new BusinessException("删除勋章失败", 500);
|
||||
}
|
||||
|
||||
// 同时软删除关联规则
|
||||
await Context.Updateable<MedalRule>()
|
||||
.SetColumns(r => new MedalRule { IsDeleted = true, UpdatedBy = "System", UpdatedAt = DateTime.Now })
|
||||
.Where(r => r.MedalId == id)
|
||||
.ExecuteCommandAsync();
|
||||
});
|
||||
}
|
||||
catch (BusinessException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "勋章删除事务失败,ID: {Id}", id);
|
||||
throw new BusinessException("删除勋章失败", 500);
|
||||
}
|
||||
|
||||
@ -182,7 +194,7 @@ public class MedalService(BaseRepository<Medal> medalRepository, ILogger<MedalSe
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据ID获取勋章
|
||||
/// 根据ID获取勋章(含规则)
|
||||
/// </summary>
|
||||
public async Task<MedalOutput> GetByIdAsync(long id)
|
||||
{
|
||||
@ -195,26 +207,12 @@ public class MedalService(BaseRepository<Medal> medalRepository, ILogger<MedalSe
|
||||
throw new BusinessException("勋章不存在", 404);
|
||||
}
|
||||
|
||||
return new MedalOutput
|
||||
{
|
||||
Id = medal.Id,
|
||||
Name = medal.Name,
|
||||
Description = medal.Description,
|
||||
ImageUrl = medal.ImageUrl,
|
||||
ConditionType = medal.ConditionType,
|
||||
ConditionValue = medal.ConditionValue,
|
||||
SortOrder = medal.SortOrder,
|
||||
Type = medal.Type,
|
||||
JournalId = medal.JournalId,
|
||||
CreatedBy = medal.CreatedBy,
|
||||
CreatedAt = medal.CreatedAt,
|
||||
UpdatedBy = medal.UpdatedBy,
|
||||
UpdatedAt = medal.UpdatedAt
|
||||
};
|
||||
var rules = await GetRulesByMedalIdAsync(medal.Id);
|
||||
return BuildMedalOutput(medal, rules);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分页查询勋章列表
|
||||
/// 分页查询勋章列表(含规则)
|
||||
/// </summary>
|
||||
public async Task<PageListModel<MedalOutput>> GetListAsync(MedalQueryInput input)
|
||||
{
|
||||
@ -231,31 +229,27 @@ public class MedalService(BaseRepository<Medal> medalRepository, ILogger<MedalSe
|
||||
}
|
||||
|
||||
RefAsync<int> totalNumber = 0;
|
||||
var pageResult = await medalRepository.Queryable()
|
||||
var medals = await medalRepository.Queryable()
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.Name), m => m.Name.Contains(input.Name))
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.Type), m => m.Type == input.Type)
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.ConditionType), m => m.ConditionType == input.ConditionType)
|
||||
.OrderBy(m => m.SortOrder, SqlSugar.OrderByType.Asc)
|
||||
.OrderBy(m => m.SortOrder)
|
||||
.OrderByDescending(m => m.CreatedAt)
|
||||
.Select(m => new MedalOutput
|
||||
{
|
||||
Id = m.Id,
|
||||
Name = m.Name,
|
||||
Description = m.Description,
|
||||
ImageUrl = m.ImageUrl,
|
||||
ConditionType = m.ConditionType,
|
||||
ConditionValue = m.ConditionValue,
|
||||
SortOrder = m.SortOrder,
|
||||
Type = m.Type,
|
||||
JournalId = m.JournalId,
|
||||
CreatedBy = m.CreatedBy,
|
||||
CreatedAt = m.CreatedAt,
|
||||
UpdatedBy = m.UpdatedBy,
|
||||
UpdatedAt = m.UpdatedAt
|
||||
}, true)
|
||||
.ToPageListAsync(input.PageIndex, input.PageSize, totalNumber);
|
||||
|
||||
return new PageListModel<MedalOutput>(pageResult, input.PageIndex, input.PageSize, totalNumber);
|
||||
// 批量查询所有勋章的规则
|
||||
var medalIds = medals.Select(m => m.Id).ToList();
|
||||
var allRules = await Context.Queryable<MedalRule>()
|
||||
.Where(r => medalIds.Contains(r.MedalId) && !r.IsDeleted)
|
||||
.ToListAsync();
|
||||
|
||||
var rulesDict = allRules.GroupBy(r => r.MedalId)
|
||||
.ToDictionary(g => g.Key, g => g.OrderBy(r => r.RuleOrder).Select(r => MapRuleOutput(r)).ToList());
|
||||
|
||||
var pageResult = medals.Select(m => BuildMedalOutput(m, rulesDict.GetValueOrDefault(m.Id))).ToList();
|
||||
|
||||
var result = new PageListModel<MedalOutput>(new List<MedalOutput>(), input.PageIndex, input.PageSize, totalNumber);
|
||||
result.Result = pageResult;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -291,6 +285,19 @@ public class MedalService(BaseRepository<Medal> medalRepository, ILogger<MedalSe
|
||||
logger.LogInformation("勋章状态更新成功,ID: {Id}, Status: {Status}", id, status);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取勋章的规则列表
|
||||
/// </summary>
|
||||
public async Task<List<MedalRuleOutput>> GetRulesByMedalIdAsync(long medalId)
|
||||
{
|
||||
var rules = await Context.Queryable<MedalRule>()
|
||||
.Where(r => r.MedalId == medalId && !r.IsDeleted)
|
||||
.OrderBy(r => r.RuleOrder)
|
||||
.ToListAsync();
|
||||
|
||||
return rules.Select(r => MapRuleOutput(r)).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有启用勋章列表(含当前用户拥有状态)
|
||||
/// </summary>
|
||||
@ -300,7 +307,7 @@ public class MedalService(BaseRepository<Medal> medalRepository, ILogger<MedalSe
|
||||
|
||||
var medals = await medalRepository.Queryable()
|
||||
.Where(m => m.Status == 1)
|
||||
.OrderBy(m => m.SortOrder, SqlSugar.OrderByType.Asc)
|
||||
.OrderBy(m => m.SortOrder)
|
||||
.OrderByDescending(m => m.CreatedAt)
|
||||
.ToListAsync();
|
||||
|
||||
@ -316,8 +323,6 @@ public class MedalService(BaseRepository<Medal> medalRepository, ILogger<MedalSe
|
||||
Name = m.Name,
|
||||
Description = m.Description,
|
||||
ImageUrl = m.ImageUrl,
|
||||
ConditionType = m.ConditionType,
|
||||
ConditionValue = m.ConditionValue,
|
||||
SortOrder = m.SortOrder,
|
||||
Type = m.Type,
|
||||
IsOwned = userMedalDict.ContainsKey((int)m.Id),
|
||||
@ -407,4 +412,91 @@ public class MedalService(BaseRepository<Medal> medalRepository, ILogger<MedalSe
|
||||
|
||||
logger.LogInformation("勋章激活成功,用户ID: {UserId}, 勋章ID: {MedalId}", userId, input.MedalId);
|
||||
}
|
||||
|
||||
#region 私有辅助方法
|
||||
|
||||
/// <summary>
|
||||
/// 批量插入规则
|
||||
/// </summary>
|
||||
private async Task InsertRulesAsync(long medalId, List<MedalRuleInput> ruleInputs)
|
||||
{
|
||||
var rules = ruleInputs.Select(r => new MedalRule
|
||||
{
|
||||
MedalId = medalId,
|
||||
TargetTable = r.TargetTable,
|
||||
TargetField = r.TargetField,
|
||||
Operator = r.Operator,
|
||||
ThresholdValue = r.ThresholdValue,
|
||||
FilterCondition = r.FilterCondition,
|
||||
DateRangeType = r.DateRangeType,
|
||||
DateRangeStart = r.DateRangeStart,
|
||||
DateRangeEnd = r.DateRangeEnd,
|
||||
LogicOperator = r.LogicOperator,
|
||||
RuleOrder = r.RuleOrder,
|
||||
Description = r.Description,
|
||||
CreatedBy = "System",
|
||||
UpdatedBy = "System",
|
||||
CreatedAt = DateTime.Now,
|
||||
UpdatedAt = DateTime.Now,
|
||||
IsDeleted = false
|
||||
}).ToList();
|
||||
|
||||
var count = await Context.Insertable(rules).ExecuteCommandAsync();
|
||||
if (count <= 0)
|
||||
{
|
||||
logger.LogError("勋章规则插入失败,MedalId: {MedalId}", medalId);
|
||||
throw new BusinessException("创建勋章规则失败", 500);
|
||||
}
|
||||
|
||||
logger.LogInformation("勋章规则创建成功,MedalId: {MedalId}, 规则数: {Count}", medalId, rules.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建MedalOutput
|
||||
/// </summary>
|
||||
private static MedalOutput BuildMedalOutput(Medal medal, List<MedalRuleOutput>? rules)
|
||||
{
|
||||
return new MedalOutput
|
||||
{
|
||||
Id = medal.Id,
|
||||
Name = medal.Name,
|
||||
Description = medal.Description,
|
||||
ImageUrl = medal.ImageUrl,
|
||||
SortOrder = medal.SortOrder,
|
||||
Type = medal.Type,
|
||||
JournalId = medal.JournalId,
|
||||
Rules = rules,
|
||||
CreatedBy = medal.CreatedBy,
|
||||
CreatedAt = medal.CreatedAt,
|
||||
UpdatedBy = medal.UpdatedBy,
|
||||
UpdatedAt = medal.UpdatedAt
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 映射规则实体到输出DTO
|
||||
/// </summary>
|
||||
private static MedalRuleOutput MapRuleOutput(MedalRule r)
|
||||
{
|
||||
return new MedalRuleOutput
|
||||
{
|
||||
Id = r.Id,
|
||||
MedalId = r.MedalId,
|
||||
TargetTable = r.TargetTable,
|
||||
TargetField = r.TargetField,
|
||||
Operator = r.Operator,
|
||||
ThresholdValue = r.ThresholdValue,
|
||||
FilterCondition = r.FilterCondition,
|
||||
DateRangeType = r.DateRangeType,
|
||||
DateRangeStart = r.DateRangeStart,
|
||||
DateRangeEnd = r.DateRangeEnd,
|
||||
LogicOperator = r.LogicOperator,
|
||||
RuleOrder = r.RuleOrder,
|
||||
Description = r.Description,
|
||||
CreatedAt = r.CreatedAt,
|
||||
UpdatedAt = r.UpdatedAt
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user