Files
QYZH.InteractiveMagazine/QYZH.InteractiveMagazine.Service/UsersService.cs
glz f8874ff60c feat: 新增微信用户名字段并优化用户数据查询及接口请求方式
1. 新增WxUserName字段到UsersOutput Dto用于存储微信用户名
2. 关联WxUser表查询以获取微信用户名数据
3. 将用户相关的GET接口修改为POST接口,使用FromBody接收参数
2026-07-03 11:24:28 +08:00

322 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using QYZH.InteractiveMagazine.IService;
using QYZH.InteractiveMagazine.Models.Common;
using QYZH.InteractiveMagazine.Models.Dto;
using QYZH.InteractiveMagazine.Models.Dto.CheckIn;
using QYZH.InteractiveMagazine.Models.Dto.Compensation;
using QYZH.InteractiveMagazine.Models.Dto.Points;
using QYZH.InteractiveMagazine.Models.Entity;
using QYZH.InteractiveMagazine.Models.Enum;
using QYZH.InteractiveMagazine.Repository;
using SqlSugar;
namespace QYZH.InteractiveMagazine.Service;
public class UsersService(
BaseRepository<Users> usersRepository,
ILogger<UsersService> _logger,
IPointsService pointsService,
ICheckInService checkInService,
ICompensationTaskService compensationTaskService,
IUserJournalService userJournalService,
IOperationLogService operationLogService) : BaseRepository<Users>, IUsersService
{
/// <summary>
/// 分页查询用户列表
/// </summary>
public async Task<BaseResponse<PageListModel<UsersOutput>>> GetListAsync(UsersQueryInput input)
{
RefAsync<int> totalNumber = 0;
var list = await Queryable()
.LeftJoin<WxUser>((u, w) => u.WxUserId == w.Id && !w.IsDeleted)
.WhereIF(!string.IsNullOrEmpty(input.WxUserId), (u, w) => u.WxUserId.ToString() == input.WxUserId)
.OrderBy((u, w) => u.Id, OrderByType.Desc)
.Select((u, w) => new UsersOutput
{
Id = u.Id,
WxUserId = u.WxUserId.ToString(),
WxUserName = w.Name,
Name = u.Name,
AvatarUrl = u.AvatarUrl,
Points = u.Points,
Type = u.Type.ToString(),
Status = u.Status.ToString(),
GrowthPoints = u.GrowthPoints,
UploadDomain = u.UploadDomain
})
.ToPageListAsync(input.PageIndex, input.PageSize, totalNumber);
var page = new PageListModel<UsersOutput>(list, input.PageIndex, input.PageSize, totalNumber);
return BaseResponse<PageListModel<UsersOutput>>.Success(page);
}
/// <summary>
/// 获取用户详情(仅基本信息)
/// </summary>
public async Task<BaseResponse<UserDetailOutput>> GetDetailAsync(long id)
{
var user = await Queryable()
.LeftJoin<WxUser>((u, w) => u.WxUserId == w.Id && !w.IsDeleted)
.Where((u, w) => u.Id == id)
.Select((u, w) => new UsersOutput
{
Id = u.Id,
WxUserId = u.WxUserId.ToString(),
WxUserName = w.Name,
Name = u.Name,
AvatarUrl = u.AvatarUrl,
Points = u.Points,
Type = u.Type.ToString(),
Status = u.Status.ToString(),
GrowthPoints = u.GrowthPoints,
UploadDomain = u.UploadDomain
})
.FirstAsync();
if (user == null)
{
return BaseResponse<UserDetailOutput>.Fail("用户不存在");
}
return BaseResponse<UserDetailOutput>.Success(new UserDetailOutput
{
BasicInfo = user
});
}
/// <summary>
/// 分页查询用户积分记录
/// </summary>
public async Task<BaseResponse<PageListModel<PointsRecordOutput>>> GetUserPointsRecordsAsync(long userId, PointsRecordQueryInput input)
{
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
{
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>
public async Task<BaseResponse<PageListModel<CompensationTaskOutput>>> GetUserCompensationTasksAsync(long userId, CompensationTaskQueryInput input)
{
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
{
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>
public async Task<BaseResponse<PageListModel<UserJournalItemOutput>>> GetUserJournalsAsync(long userId, UserJournalQueryInput input)
{
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 journals = await Context.Queryable<Journal>()
.Where(j => journalIds.Contains(j.Id) && !j.IsDeleted)
.ToListAsync();
var journalDict = journals.ToDictionary(j => j.Id);
foreach (var item in items)
{
if (journalDict.TryGetValue(item.JournalId, out var journal))
{
item.Name = journal.Name;
item.CoverImageUrl = journal.Cover;
}
}
}
var page = new PageListModel<UserJournalItemOutput>(items, input.PageIndex, input.PageSize, total);
return BaseResponse<PageListModel<UserJournalItemOutput>>.Success(page);
}
/// <summary>
/// 更新用户状态
/// </summary>
public async Task<BaseResponse> UpdateStatusAsync(long id)
{
var exists = await usersRepository.GetByIdAsync(id);
if (exists == null)
{
return BaseResponse.Fail("用户不存在");
}
var statusValue = exists.Status == (int)UserStatusEnum.Active ? UserStatusEnum.Disabled : UserStatusEnum.Active;
var result = await UpdateAsync(
u => new Users { Status = (int)statusValue },
u => u.Id == id
);
return result ? BaseResponse.Success() : BaseResponse.Fail("更新失败");
}
/// <summary>
/// 手动增加用户积分
/// </summary>
public async Task<ManualPointsOutput> ManualAddPointsAsync(long userId, ManualAddPointsInput input, long operatorId, string operatorName, string? ipAddress = null)
{
_logger.LogInformation("管理员手动增加积分UserId: {UserId}, Amount: {Amount}, Operator: {Operator}",
userId, input.Amount, operatorName);
// 校验用户是否存在
var user = await Queryable().Where(u => u.Id == userId && !u.IsDeleted).FirstAsync();
if (user == null)
throw new BusinessException("用户不存在", ResultCode.NOT_FOUND);
// 调用积分服务增加积分
var result = await pointsService.AddPointsAsync(new AddPointsInput
{
UserId = userId,
Amount = input.Amount,
ChangeType = PointsChangeTypeEnum.ManualAdjust,
Description = $"管理员手动增加: {input.Reason}",
OperatorName = operatorName
});
// 记录操作日志
var detail = JsonConvert.SerializeObject(new
{
Amount = input.Amount,
Reason = input.Reason,
PreviousBalance = result.PreviousBalance,
NewBalance = result.NewBalance,
RecordId = result.RecordId
});
await operationLogService.LogAsync(
operatorId, operatorName,
OperationLogActionType.ManualAddPoints,
OperationLogTargetType.User,
userId, user.Name, detail, ipAddress);
return new ManualPointsOutput
{
RecordId = result.RecordId,
PreviousBalance = result.PreviousBalance,
NewBalance = result.NewBalance,
ChangeAmount = input.Amount,
OperatorName = operatorName,
OperatedAt = DateTime.Now
};
}
/// <summary>
/// 手动扣除用户积分
/// </summary>
public async Task<ManualPointsOutput> ManualDeductPointsAsync(long userId, ManualDeductPointsInput input, long operatorId, string operatorName, string? ipAddress = null)
{
_logger.LogInformation("管理员手动扣除积分UserId: {UserId}, Amount: {Amount}, Operator: {Operator}",
userId, input.Amount, operatorName);
// 校验用户是否存在
var user = await Queryable().Where(u => u.Id == userId && !u.IsDeleted).FirstAsync();
if (user == null)
throw new BusinessException("用户不存在", ResultCode.NOT_FOUND);
// 调用积分服务扣除积分
var result = await pointsService.DeductPointsAsync(new DeductPointsInput
{
UserId = userId,
Amount = input.Amount,
ChangeType = PointsChangeTypeEnum.ManualAdjust,
Description = $"管理员手动扣除: {input.Reason}",
OperatorName = operatorName
});
// 记录操作日志
var detail = JsonConvert.SerializeObject(new
{
Amount = input.Amount,
Reason = input.Reason,
PreviousBalance = result.PreviousBalance,
NewBalance = result.NewBalance,
RecordId = result.RecordId
});
await operationLogService.LogAsync(
operatorId, operatorName,
OperationLogActionType.ManualDeductPoints,
OperationLogTargetType.User,
userId, user.Name, detail, ipAddress);
return new ManualPointsOutput
{
RecordId = result.RecordId,
PreviousBalance = result.PreviousBalance,
NewBalance = result.NewBalance,
ChangeAmount = -input.Amount,
OperatorName = operatorName,
OperatedAt = DateTime.Now
};
}
}