using YD_Event.Application.AppUser.Dtos; using YD_Event.Application.Auth; using YD_Event.Core.Entities; using AppUserEntity = YD_Event.Core.Entities.AppUser; using YD_Event.Core.Enum; using Mapster; using EasyCaching.Core; namespace YD_Event.Application.AppUser; /// /// 普通用户服务 /// public class AppUserService : BaseService, ITransient { private readonly ISqlSugarRepository _appUserRep; private readonly ISqlSugarClient _db; private readonly AuthManager _authManager; private readonly IEasyCachingProvider _cachingProvider; public AppUserService(ISqlSugarRepository appUserRep, ISqlSugarClient db, AuthManager authManager, IEasyCachingProvider cachingProvider) : base(appUserRep) { _appUserRep = appUserRep; _db = db; _authManager = authManager; _cachingProvider = cachingProvider; } /// /// 分页查询普通用户 /// /// /// [DisplayName("分页查询普通用户")] [HttpGet("page")] public async Task> Page([FromQuery] AppUserPageInput input) { var query = _appUserRep.AsQueryable() .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name)) .WhereIF(input.Gender.HasValue, u => u.Gender == input.Gender) .WhereIF(!string.IsNullOrWhiteSpace(input.Mobile), u => u.Mobile.Contains(input.Mobile)) .WhereIF(input.AuditStatus.HasValue, u => u.AuditStatus == input.AuditStatus) .WhereIF(input.StartTime.HasValue, u => u.CreatedTime >= input.StartTime) .WhereIF(input.EndTime.HasValue, u => u.CreatedTime <= input.EndTime) .OrderByDescending(u => u.CreatedTime); return await query.Select().ToPagedListAsync(input); } /// /// 获取普通用户详情 /// /// /// [DisplayName("获取普通用户详情")] [HttpGet("{id}")] public async Task Detail([FromRoute] long id) { return await _appUserRep.AsQueryable() .Where(u => u.Id == id) .Select() .FirstAsync(); } /// /// 审核普通用户 /// /// /// [DisplayName("审核普通用户")] [HttpPost("audit")] [UnitOfWork] public async Task Audit([FromBody] AuditInput input) { if (input.Ids == null || !input.Ids.Any()) return; // 更新状态 await _appUserRep.UpdateAsync(u => new AppUserEntity { AuditStatus = input.Status, AuditRemark = input.Remark, UpdatedTime = DateTime.Now, UpdatedUserId = _authManager.UserId }, u => input.Ids.Contains(u.Id)); } #region 统一成员管理 (领队/教练/运动员) /// /// 统一分页查询成员 /// /// /// [HttpGet("member/page")] [DisplayName("统一分页查询成员")] public async Task> MemberPage([FromQuery] MemberQueryInput input) { var (userId, merchantCertificationId) = await GetCurrentUserAndMerchantCertificationId(); var query = _appUserRep.AsQueryable() .Where(x => x.PersonType == input.PersonType && !x.DeleteMark) .WhereIF(!string.IsNullOrWhiteSpace(input.Name), x => x.Name.Contains(input.Name)) .WhereIF(input.Gender.HasValue, x => x.Gender == input.Gender) .WhereIF(!string.IsNullOrWhiteSpace(input.Mobile), x => x.Mobile.Contains(input.Mobile)) .WhereIF(!string.IsNullOrWhiteSpace(input.IdCardNumber), u => u.IdCardNumber.Contains(input.IdCardNumber)) .WhereIF(input.PersonType == PersonType.Coach && !string.IsNullOrWhiteSpace(input.SkillLevel), x => x.SkillLevel == input.SkillLevel) .WhereIF(input.PersonType == PersonType.Coach && input.CertificationStatus.HasValue, x => x.CertificationStatus == input.CertificationStatus) .WhereIF(input.StartTime.HasValue, u => u.CreatedTime >= input.StartTime) .WhereIF(input.EndTime.HasValue, u => u.CreatedTime <= input.EndTime) .OrderByDescending(x => x.CreatedTime); // 权限过滤 (管理员可看全部,这里简化的商户隔离逻辑) if (merchantCertificationId.HasValue) { query = query.Where(x => x.MerchantCertificationId == merchantCertificationId.Value); } else { // 这里根据实际业务,如果普通用户只能看自己创建的,需要这个过滤 query = query.Where(x => x.CreatedUserId == userId && x.MerchantCertificationId == null); } var list = await query.ToPagedListAsync(input); var result = list.Adapt>(); // 设置Age字段:优先使用数据库中的Age,如果没有则根据BirthDate计算 foreach (var item in result.Rows) { if (item.Age.HasValue) { // 数据库中已有Age,直接使用 continue; } // 数据库中没有Age,根据BirthDate动态计算 if (item.BirthDate.HasValue) { item.Age = MemberOutput.CalculateAgeFromBirthDate(item.BirthDate); } } return result; } /// /// 统一新增/编辑成员 /// /// /// [HttpPost("member/save")] [DisplayName("统一新增/编辑成员")] public async Task SaveUnifiedMember(CreateOrUpdateMemberInput input) { // 仅在新增运动员时验证验证码 if (!input.Id.HasValue && input.PersonType == PersonType.Athlete) { if (string.IsNullOrWhiteSpace(input.VerificationCode)) { throw Oops.Bah("验证码不能为空"); } var cacheKey = $"sms:code:{input.Mobile}"; var cachedCodeResult = _cachingProvider.Get(cacheKey); string? cachedCode = cachedCodeResult.Value; if (!cachedCodeResult.HasValue || cachedCode != input.VerificationCode) { throw Oops.Bah("验证码错误或已过期"); } } var (userId, merchantCertificationId) = await GetCurrentUserAndMerchantCertificationId(); // 基于手机号的全局唯一性校验(不区分PersonType和权限) var existingByPhone = await _appUserRep.AsQueryable() .Where(x => x.Mobile == input.Mobile && !x.DeleteMark) .FirstAsync(); AppUserEntity entity; bool isNewRecord = false; if (input.Id.HasValue) { // 编辑模式 entity = await _appUserRep.GetByIdAsync(input.Id.Value); if (entity == null || entity.DeleteMark) throw Oops.Bah("成员不存在"); await CheckPermission(entity); // 检查手机号是否被其他记录占用 if (existingByPhone != null && existingByPhone.Id != input.Id.Value) { throw Oops.Bah($"该手机号已被其他成员使用"); } entity.UpdatedUserId = _authManager.UserId; entity.UpdatedTime = DateTime.Now; } else if (existingByPhone != null) { // 手机号已存在,更新现有记录 entity = existingByPhone; // 检查权限 await CheckPermission(entity); entity.UpdatedUserId = _authManager.UserId; entity.UpdatedTime = DateTime.Now; } else { // 手机号不存在,创建新记录 isNewRecord = true; entity = new AppUserEntity { Id = YitIdHelper.NextId(), PersonType = input.PersonType, MerchantCertificationId = merchantCertificationId, CreatedUserId = userId, CreatedTime = DateTime.Now, Status = AvailabilityStatus.Enable, AuditStatus = AuditStatus.Pass }; } // 更新用户信息字段 entity.Name = input.Name; entity.Gender = input.Gender; entity.IdCardNumber = input.IdCardNumber; entity.IdCardImageUrl = input.IdCardImageUrl; entity.PassportPhotoUrl = input.PassportPhotoUrl; entity.Mobile = input.Mobile; entity.Remark = input.Remark; entity.AuditRemark = ""; // 保存出生日期 entity.BirthDate = input.BirthDate; // 保存年龄字段:如果用户填写了年龄,直接保存;如果没有填写但有出生日期,可以在查询时动态计算 entity.Age = input.Age; // 更新运动员类型(如果是新记录或需要更新) if (isNewRecord || entity.PersonType != input.PersonType) { entity.PersonType = input.PersonType; } // 更新认证单位信息 if (isNewRecord || entity.MerchantCertificationId != merchantCertificationId) { entity.MerchantCertificationId = merchantCertificationId; } if (input.PersonType == PersonType.Coach) { entity.SkillLevel = input.SkillLevel; entity.CertificationStatus = input.CertificationStatus; } await _appUserRep.InsertOrUpdateAsync(entity); } #endregion #region 领队/教练管理 (向下兼容) private async Task<(long userId, long? merchantCertificationId)> GetCurrentUserAndMerchantCertificationId() { var userId = _authManager.UserId; // 直接查询单位认证表,检查是否有审核通过的认证记录 var certification = await _db.Queryable() .FirstAsync(c => c.UserId == userId && !c.DeleteMark); // 有审核通过的认证就返回认证ID,否则返回null return (userId, certification?.Id); } private async Task CheckPermission(AppUserEntity entity) { var (userId, merchantCertificationId) = await GetCurrentUserAndMerchantCertificationId(); if (merchantCertificationId.HasValue) { if (entity.MerchantCertificationId != merchantCertificationId.Value) throw Oops.Bah("无权操作该成员"); } else { if (entity.CreatedUserId != userId || entity.MerchantCertificationId != null) throw Oops.Bah("无权操作该成员"); } } /// /// 删除成员 /// /// /// [DisplayName("删除成员")] [HttpPost("member/delete")] public async Task DeleteMember([FromBody] long id) { var entity = await _appUserRep.GetByIdAsync(id); if (entity == null || entity.DeleteMark) throw Oops.Bah("成员不存在"); await CheckPermission(entity); entity.DeleteMark = true; entity.UpdatedUserId = _authManager.UserId; entity.UpdatedTime = DateTime.Now; await _appUserRep.UpdateAsync(entity); } /// /// 批量删除成员 /// /// /// [HttpPost("member/batchDelete")] [DisplayName("批量删除成员")] public async Task BatchDeleteMember([FromBody] List ids) { if (ids == null || !ids.Any()) throw Oops.Bah("请选择要删除的记录"); // 逻辑删除 await _appUserRep.UpdateAsync(x => new AppUserEntity { DeleteMark = true }, x => ids.Contains(x.Id)); } /// /// 变更成员状态 /// /// /// [DisplayName("变更成员状态")] [HttpPost("member/status")] public async Task ChangeMemberStatus(ChangeMemberStatusInput input) { var entity = await _appUserRep.GetByIdAsync(input.Id); if (entity == null || entity.DeleteMark) throw Oops.Bah("成员不存在"); await CheckPermission(entity); entity.Status = input.Status; entity.UpdatedUserId = _authManager.UserId; entity.UpdatedTime = DateTime.Now; await _appUserRep.UpdateAsync(entity); } #endregion }