feat: 完成多模块功能迭代与优化
1. 新增宠物皮肤初始枚举值、下拉列表接口及相关DTO 2. 完善商品实体与DTO,新增虚拟商品标记和类型ID字段 3. 重构用户认证体系,支持多用户切换并重新生成JWT令牌 4. 新增签到配置管理全套功能,包括增删改查和状态管理 5. 优化模型验证过滤器和基础响应类的命名规范 6. 新增补签功能,完善签到服务逻辑 7. 拆分用户详情DTO,新增各子数据分页查询接口 8. 重构微信控制器的用户ID获取逻辑,统一使用激活用户ID 9. 修复背包服务中补签卡的扣减逻辑 10. 新增家长姓名修改接口和相关服务实现
This commit is contained in:
@ -37,7 +37,7 @@ public class UsersService(
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户详情(包含积分记录、签到记录、补偿任务、期刊列表)
|
||||
/// 获取用户详情(仅基本信息)
|
||||
/// </summary>
|
||||
public async Task<BaseResponse<UserDetailOutput>> GetDetailAsync(long id)
|
||||
{
|
||||
@ -47,125 +47,124 @@ public class UsersService(
|
||||
return BaseResponse<UserDetailOutput>.Fail("用户不存在");
|
||||
}
|
||||
|
||||
// 并行查询关联数据
|
||||
var pointsTask = GetPointsRecordsAsync(id);
|
||||
var checkInTask = GetCheckInRecordsAsync(id);
|
||||
var compensationTask = GetFailedCompensationTasksAsync(id);
|
||||
var journalsTask = GetUserJournalsWithDetailAsync(id);
|
||||
|
||||
await Task.WhenAll(pointsTask, checkInTask, compensationTask, journalsTask);
|
||||
|
||||
return BaseResponse<UserDetailOutput>.Success(new UserDetailOutput
|
||||
{
|
||||
BasicInfo = user,
|
||||
PointsRecords = await pointsTask,
|
||||
CheckInRecords = await checkInTask,
|
||||
FailedCompensationTasks = await compensationTask,
|
||||
Journals = await journalsTask
|
||||
BasicInfo = user
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户积分记录(最近20条)
|
||||
/// 分页查询用户积分记录
|
||||
/// </summary>
|
||||
private async Task<List<PointsRecordOutput>> GetPointsRecordsAsync(long userId)
|
||||
public async Task<BaseResponse<PageListModel<PointsRecordOutput>>> GetUserPointsRecordsAsync(long userId, PointsRecordQueryInput input)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await pointsService.GetPointsRecordsAsync(new PointsRecordQueryInput
|
||||
input.UserId = userId;
|
||||
var result = await pointsService.GetPointsRecordsAsync(input);
|
||||
return BaseResponse<PageListModel<PointsRecordOutput>>.Success(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分页查询用户签到记录
|
||||
/// </summary>
|
||||
public async Task<BaseResponse<PageListModel<CheckInRecordOutput>>> GetUserCheckInRecordsAsync(long userId, PageQueryModel input)
|
||||
{
|
||||
RefAsync<int> total = 0;
|
||||
var records = await Context.Queryable<CheckInRecord>()
|
||||
.Where(r => r.UserId == userId && !r.IsDeleted)
|
||||
.OrderBy(r => r.CheckInDate, OrderByType.Desc)
|
||||
.Select(r => new CheckInRecordOutput
|
||||
{
|
||||
UserId = userId,
|
||||
PageIndex = 1,
|
||||
PageSize = 20
|
||||
});
|
||||
return result.Result ?? [];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "获取用户积分记录失败,UserId: {UserId}", userId);
|
||||
return [];
|
||||
}
|
||||
Id = (long)r.Id,
|
||||
CheckInDate = r.CheckInDate,
|
||||
CreatedAt = r.CreatedAt,
|
||||
ConsecutiveDays = r.ConsecutiveDays,
|
||||
PointsAwarded = r.PointsAwarded,
|
||||
GrowthPointsAwarded = r.GrowthPointsAwarded,
|
||||
Type = r.Type.ToString(),
|
||||
Status = r.Status.ToString()
|
||||
})
|
||||
.ToPageListAsync(input.PageIndex, input.PageSize, total);
|
||||
|
||||
var page = new PageListModel<CheckInRecordOutput>(records, input.PageIndex, input.PageSize, total);
|
||||
return BaseResponse<PageListModel<CheckInRecordOutput>>.Success(page);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户签到记录
|
||||
/// 分页查询用户补偿任务
|
||||
/// </summary>
|
||||
private async Task<List<CheckInRecordOutput>> GetCheckInRecordsAsync(long userId)
|
||||
public async Task<BaseResponse<PageListModel<CompensationTaskOutput>>> GetUserCompensationTasksAsync(long userId, CompensationTaskQueryInput input)
|
||||
{
|
||||
try
|
||||
{
|
||||
var info = await checkInService.GetCheckInInfoAsync(userId);
|
||||
return info.RecentRecords ?? [];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "获取用户签到记录失败,UserId: {UserId}", userId);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户失败的补偿任务(需要手动处理)
|
||||
/// </summary>
|
||||
private async Task<List<CompensationTaskOutput>> GetFailedCompensationTasksAsync(long userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var tasks = await compensationTaskService.GetTasksAsync(new GetCompensationTasksInput
|
||||
RefAsync<int> total = 0;
|
||||
var tasks = await Context.Queryable<CompensationTask>()
|
||||
.Where(t => t.UserId == userId && !t.IsDeleted)
|
||||
.WhereIF(input.Status.HasValue, t => t.Status == (int)input.Status)
|
||||
.WhereIF(input.TaskType.HasValue, t => t.TaskType == (int)input.TaskType)
|
||||
.WhereIF(!string.IsNullOrEmpty(input.BusinessSource), t => t.BusinessSource == input.BusinessSource)
|
||||
.OrderBy(t => t.CreatedAt, OrderByType.Desc)
|
||||
.Select(t => new CompensationTaskOutput
|
||||
{
|
||||
UserId = userId,
|
||||
Status = CompensationTaskStatusEnum.Failed,
|
||||
Limit = 20
|
||||
});
|
||||
return tasks;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "获取用户失败补偿任务失败,UserId: {UserId}", userId);
|
||||
return [];
|
||||
}
|
||||
Id = t.Id,
|
||||
TaskType = (CompensationTaskTypeEnum)t.TaskType,
|
||||
BusinessSource = t.BusinessSource,
|
||||
BusinessId = t.BusinessId,
|
||||
UserId = t.UserId,
|
||||
Payload = t.Payload,
|
||||
ErrorMessage = t.ErrorMessage,
|
||||
ErrorSource = t.ErrorSource,
|
||||
RetryCount = t.RetryCount,
|
||||
MaxRetries = t.MaxRetries,
|
||||
Status = (CompensationTaskStatusEnum)t.Status,
|
||||
ProcessedAt = t.ProcessedAt,
|
||||
ScheduledAt = t.ScheduledAt,
|
||||
ResultMessage = t.ResultMessage,
|
||||
CreatedAt = t.CreatedAt
|
||||
})
|
||||
.ToPageListAsync(input.PageIndex, input.PageSize, total);
|
||||
|
||||
var page = new PageListModel<CompensationTaskOutput>(tasks, input.PageIndex, input.PageSize, total);
|
||||
return BaseResponse<PageListModel<CompensationTaskOutput>>.Success(page);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户拥有的期刊列表(含期刊详情)
|
||||
/// 分页查询用户期刊列表(含期刊详情)
|
||||
/// </summary>
|
||||
private async Task<List<UserJournalItemOutput>> GetUserJournalsWithDetailAsync(long userId)
|
||||
public async Task<BaseResponse<PageListModel<UserJournalItemOutput>>> GetUserJournalsAsync(long userId, UserJournalQueryInput input)
|
||||
{
|
||||
try
|
||||
RefAsync<int> total = 0;
|
||||
var items = await Context.Queryable<UserJournal>()
|
||||
.Where(uj => uj.UserId == userId && !uj.IsDeleted)
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.Type), uj => uj.Type.ToString() == input.Type)
|
||||
.OrderByDescending(uj => uj.CreatedAt)
|
||||
.Select(uj => new UserJournalItemOutput
|
||||
{
|
||||
BindId = uj.Id,
|
||||
JournalId = uj.JournalId,
|
||||
Type = uj.Type.ToString(),
|
||||
Status = uj.Status.ToString(),
|
||||
CreatedAt = uj.CreatedAt
|
||||
})
|
||||
.ToPageListAsync(input.PageIndex, input.PageSize, total);
|
||||
|
||||
// 填充期刊详情(标题、封面)
|
||||
var journalIds = items.Select(i => i.JournalId).Distinct().ToList();
|
||||
if (journalIds.Count > 0)
|
||||
{
|
||||
var userJournals = await Context.Queryable<UserJournal>()
|
||||
.Where(uj => uj.UserId == userId && !uj.IsDeleted)
|
||||
.OrderByDescending(uj => uj.CreatedAt)
|
||||
var journals = await Context.Queryable<Journal>()
|
||||
.Where(j => journalIds.Contains(j.Id) && !j.IsDeleted)
|
||||
.ToListAsync();
|
||||
|
||||
var result = new List<UserJournalItemOutput>();
|
||||
foreach (var uj in userJournals)
|
||||
var journalDict = journals.ToDictionary(j => j.Id);
|
||||
foreach (var item in items)
|
||||
{
|
||||
var journal = await Context.Queryable<Journal>()
|
||||
.Where(j => j.Id == uj.JournalId && !j.IsDeleted)
|
||||
.FirstAsync();
|
||||
|
||||
if (journal != null)
|
||||
if (journalDict.TryGetValue(item.JournalId, out var journal))
|
||||
{
|
||||
result.Add(new UserJournalItemOutput
|
||||
{
|
||||
BindId = uj.Id,
|
||||
JournalId = uj.JournalId,
|
||||
JournalTitle = journal.Title,
|
||||
CoverImageUrl = journal.CoverImageUrl,
|
||||
Type = uj.Type.ToString(),
|
||||
Status = uj.Status.ToString(),
|
||||
CreatedAt = uj.CreatedAt
|
||||
});
|
||||
item.JournalTitle = journal.Title;
|
||||
item.CoverImageUrl = journal.CoverImageUrl;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "获取用户期刊列表失败,UserId: {UserId}", userId);
|
||||
return [];
|
||||
}
|
||||
|
||||
var page = new PageListModel<UserJournalItemOutput>(items, input.PageIndex, input.PageSize, total);
|
||||
return BaseResponse<PageListModel<UserJournalItemOutput>>.Success(page);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user