diff --git a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain.Shared/Etos/BindAccountEto.cs b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain.Shared/Etos/BindAccountEto.cs new file mode 100644 index 00000000..0ab6ad5b --- /dev/null +++ b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain.Shared/Etos/BindAccountEto.cs @@ -0,0 +1,10 @@ +namespace Yi.Framework.Bbs.Domain.Shared.Etos; + +/// +/// 临时用户绑定到正式用户 +/// +public class BindAccountEto +{ + public Guid NewUserId { get; set; } + public Guid OldUserId { get; set; } +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain/EventHandlers/BindAccountForBbsEventHandler.cs b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain/EventHandlers/BindAccountForBbsEventHandler.cs new file mode 100644 index 00000000..e6fc1257 --- /dev/null +++ b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Domain/EventHandlers/BindAccountForBbsEventHandler.cs @@ -0,0 +1,47 @@ +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus; +using Yi.Framework.Bbs.Domain.Entities; +using Yi.Framework.Bbs.Domain.Shared.Etos; +using Yi.Framework.Rbac.Domain.Entities; +using Yi.Framework.SqlSugarCore.Abstractions; + +namespace Yi.Framework.Bbs.Domain.EventHandlers; + +/// +/// 临时账号绑定到正式账号,钱钱 (累加),禁用临时账号(修改) +/// +public class BindAccountForBbsEventHandler : ILocalEventHandler, ITransientDependency +{ + private readonly ISqlSugarRepository _bbsUserRepository; + private readonly ISqlSugarRepository _userRepository; + + public BindAccountForBbsEventHandler(ISqlSugarRepository bbsUserRepository, + ISqlSugarRepository userRepository) + { + _bbsUserRepository = bbsUserRepository; + _userRepository = userRepository; + } + + public async Task HandleEventAsync(BindAccountEto eventData) + { + //禁用临时用户 + var oldUser = await _userRepository.GetFirstAsync(x => x.Id == eventData.OldUserId); + if (oldUser is null || oldUser.State == false) + { + throw new UserFriendlyException("无法将无效用户进行绑定"); + } + + oldUser.State = false; + await _userRepository.UpdateAsync(oldUser); + + + //账户钱转移 + var bbsOldUser = await _bbsUserRepository.GetFirstAsync(x => x.UserId == eventData.OldUserId); + var bbsNewUser = await _bbsUserRepository.GetFirstAsync(x => x.UserId == eventData.NewUserId); + if (bbsNewUser is not null) + { + bbsNewUser.Money += bbsOldUser?.Money ?? 0; + await _bbsUserRepository.UpdateAsync(bbsNewUser); + } + } +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application.Contracts/Dtos/InvitationCode/InvitationCodeGetOutputDto.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application.Contracts/Dtos/InvitationCode/InvitationCodeGetOutputDto.cs new file mode 100644 index 00000000..ead2e169 --- /dev/null +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application.Contracts/Dtos/InvitationCode/InvitationCodeGetOutputDto.cs @@ -0,0 +1,20 @@ +namespace Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.InvitationCode; + +public class InvitationCodeGetOutputDto +{ + /// + /// 是否填写了邀请码(是否被邀请) + /// + public bool IsInvited { get; set; } + + + /// + /// 积分-邀请数量 + /// + public int PointsNumber { get; set; } + + /// + /// 邀请码 + /// + public string InvitationCode { get; set; } +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Services/Account/WeChatMiniProgramAccountService.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Services/Account/WeChatMiniProgramAccountService.cs index ae8ba5bf..5e178198 100644 --- a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Services/Account/WeChatMiniProgramAccountService.cs +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Services/Account/WeChatMiniProgramAccountService.cs @@ -1,8 +1,13 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using Volo.Abp.Application.Services; +using Volo.Abp.EventBus.Local; +using Volo.Abp.Users; +using Yi.Framework.Bbs.Domain.Shared.Etos; using Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.Account; using Yi.Framework.DigitalCollectibles.Domain.Shared.Consts; using Yi.Framework.DigitalCollectibles.Domain.Shared.Enums; +using Yi.Framework.DigitalCollectibles.Domain.Shared.Etos; using Yi.Framework.Rbac.Application.Contracts.Dtos.Account; using Yi.Framework.Rbac.Application.Contracts.IServices; using Yi.Framework.Rbac.Domain.Shared.Enums; @@ -19,13 +24,14 @@ public class WeChatMiniProgramAccountService : ApplicationService private readonly IWeChatMiniProgramManager _weChatMiniProgramManager; private readonly IAuthService _authService; private readonly IAccountService _accountService; - + private readonly ILocalEventBus _localEventBus; public WeChatMiniProgramAccountService(IWeChatMiniProgramManager weChatMiniProgramManager, IAuthService authService, - IAccountService accountService) + IAccountService accountService, ILocalEventBus localEventBus) { _weChatMiniProgramManager = weChatMiniProgramManager; _authService = authService; _accountService = accountService; + _localEventBus = localEventBus; } /// @@ -63,8 +69,11 @@ public class WeChatMiniProgramAccountService : ApplicationService /// /// [HttpPost("wechat/mini-program/account/bind")] + [Authorize] public async Task PostBindAsync(BindInput input) { + var userId = CurrentUser.GetId(); + //验证手机号 await _accountService.ValidationPhoneCaptchaAsync(ValidationPhoneTypeEnum.Bind, input.Phone, input.Code); //校验手机号与验证码 @@ -80,8 +89,17 @@ public class WeChatMiniProgramAccountService : ApplicationService //验证手机号的验证码 var openId = (await _weChatMiniProgramManager.Code2SessionAsync(new Code2SessionInput(input.JsCode))).openid; - await PostBindToAuthAsync(userInfo.User.Id, openId, userInfo.User.UserName); + + //发送账号绑定的事件,不同领域对账号数据进行迁移 + //bbs:钱钱 (累加),禁用临时账号(修改) + //dc: 价值、积分 (累加) + await _localEventBus.PublishAsync(new BindAccountEto + { + NewUserId = userInfo.User.Id, + OldUserId = userId + },false); + } private async Task PostBindToAuthAsync(Guid userId, string openId, string? name = null) diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Services/InvitationCodeService.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Services/InvitationCodeService.cs index 1fa2be68..f76c927b 100644 --- a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Services/InvitationCodeService.cs +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Application/Services/InvitationCodeService.cs @@ -2,7 +2,9 @@ using Microsoft.AspNetCore.Mvc; using Volo.Abp.Application.Services; using Volo.Abp.Users; +using Yi.Framework.DigitalCollectibles.Application.Contracts.Dtos.InvitationCode; using Yi.Framework.DigitalCollectibles.Domain.Entities; +using Yi.Framework.DigitalCollectibles.Domain.Managers; using Yi.Framework.SqlSugarCore.Abstractions; namespace Yi.Framework.DigitalCollectibles.Application.Services; @@ -12,11 +14,11 @@ namespace Yi.Framework.DigitalCollectibles.Application.Services; /// public class InvitationCodeService : ApplicationService { - private readonly ISqlSugarRepository _repository; + private readonly InvitationCodeManager _invitationCodeManager; - public InvitationCodeService(ISqlSugarRepository repository) + public InvitationCodeService(InvitationCodeManager invitationCodeManager) { - _repository = repository; + _invitationCodeManager = invitationCodeManager; } /// @@ -24,16 +26,17 @@ public class InvitationCodeService : ApplicationService /// /// [Authorize] - public async Task GetAsync() + public async Task GetAsync() { var userId = CurrentUser.GetId(); - var entity = await _repository.GetFirstAsync(x => x.UserId == userId); - if (entity is null) + var entity = await _invitationCodeManager.TryGetOrAddAsync(userId); + var output = new InvitationCodeGetOutputDto { - return new { IsInvited=false, PointsNumber=0 }; - } - - return new { entity.IsInvited, entity.PointsNumber }; + IsInvited = entity.IsInvited, + PointsNumber = entity.PointsNumber, + InvitationCode = entity.InvitationCode + }; + return output; } /// @@ -42,48 +45,10 @@ public class InvitationCodeService : ApplicationService /// /// [Authorize] - public async Task SetAsync([FromQuery] Guid invitedUserId) + [HttpPost("invitation-code/{code}")] + public async Task SetAsync([FromRoute] string code) { var userId = CurrentUser.GetId(); - var entity = await _repository.GetFirstAsync(x => x.UserId == userId); - if (entity is null) - { - await _repository.InsertAsync(new InvitationCodeAggregateRoot - { - UserId = userId, - IsInvited = true, - PointsNumber = 0 - }); - } - else - { - if (entity.IsInvited) - { - throw new UserFriendlyException("你已填写过邀请码,无法再次填写"); - } - else - { - entity.IsInvited = false; - await _repository.UpdateAsync(entity); - } - } - - - var invitedEntity = await _repository.GetFirstAsync(x => x.UserId == invitedUserId); - - if (entity is null) - { - await _repository.InsertAsync(new InvitationCodeAggregateRoot - { - UserId = invitedUserId, - IsInvited = false, - PointsNumber = 1 - }); - } - else - { - invitedEntity.PointsNumber += 1; - await _repository.UpdateAsync(invitedEntity); - } + await _invitationCodeManager.SetAsync(userId, code); } } \ No newline at end of file diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Entities/CollectiblesUserExtraInfoEntity.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Entities/CollectiblesUserExtraInfoEntity.cs deleted file mode 100644 index e0dd6e5f..00000000 --- a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Entities/CollectiblesUserExtraInfoEntity.cs +++ /dev/null @@ -1,27 +0,0 @@ -using SqlSugar; -using Volo.Abp.Domain.Entities; - -namespace Yi.Framework.DigitalCollectibles.Domain.Entities; - - -/// -/// 藏品用户信息表 -/// -[SugarTable("DC_CollectiblesUserExtraInfo")] -public class CollectiblesUserExtraInfoEntity: Entity -{ - /// - /// 用户id - /// - public Guid UserId { get; set; } - - /// - /// 手机号 - /// - public string Phone{ get; set; } - - /// - /// 微信openid - /// - public string WeChatOpenId { get; set; } -} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Entities/InvitationCodeAggregateRoot.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Entities/InvitationCodeAggregateRoot.cs index 6694cd5c..277df7bb 100644 --- a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Entities/InvitationCodeAggregateRoot.cs +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Entities/InvitationCodeAggregateRoot.cs @@ -4,8 +4,18 @@ using Volo.Abp.Domain.Entities.Auditing; namespace Yi.Framework.DigitalCollectibles.Domain.Entities; [SugarTable("DC_InvitationCode")] -public class InvitationCodeAggregateRoot:FullAuditedAggregateRoot +public class InvitationCodeAggregateRoot : FullAuditedAggregateRoot { + public InvitationCodeAggregateRoot() + { + } + public InvitationCodeAggregateRoot(Guid userId, string invitationCode) + { + this.UserId = userId; + this.InvitationCode = invitationCode; + } + + /// /// 谁的邀请码 /// @@ -14,14 +24,35 @@ public class InvitationCodeAggregateRoot:FullAuditedAggregateRoot /// /// 是否填写了邀请码(是否被邀请) /// - public bool IsInvited { get; set; } + public bool IsInvited { get; set; } = false; /// /// 积分-邀请数量 /// - public int PointsNumber { get; set; } + public int PointsNumber { get; set; } = 0; + /// + /// 邀请码 + /// + public string InvitationCode { get; set; } + + /// + /// 这个人填写了邀请码(不能再进行填写) + /// + public void SetInvite() + { + IsInvited = true; + + } + + /// + /// 别人填写了这个用户的邀请码(这个用户积分+1) + /// + public void SetInvited() + { + PointsNumber += 1; + } //不做记录 // /// diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/EventHandlers/BindAccountForCollectiblesEventHandler.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/EventHandlers/BindAccountForCollectiblesEventHandler.cs new file mode 100644 index 00000000..9e1f808d --- /dev/null +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/EventHandlers/BindAccountForCollectiblesEventHandler.cs @@ -0,0 +1,93 @@ +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus; +using Yi.Framework.Bbs.Domain.Shared.Etos; +using Yi.Framework.DigitalCollectibles.Domain.Entities; +using Yi.Framework.DigitalCollectibles.Domain.Entities.Record; +using Yi.Framework.DigitalCollectibles.Domain.Managers; +using Yi.Framework.DigitalCollectibles.Domain.Shared.Etos; +using Yi.Framework.SqlSugarCore.Abstractions; + +namespace Yi.Framework.DigitalCollectibles.Domain.EventHandlers; + +/// +/// 临时账号绑定到正式账号,价值、积分 (累加) +/// +public class BindAccountForCollectiblesEventHandler : ILocalEventHandler, ITransientDependency +{ + private readonly InvitationCodeManager _invitationCodeManager; + + private readonly ISqlSugarRepository _collectiblesUserStoreRepository; + + + private readonly ISqlSugarRepository _miningPoolRecordRepository; + private readonly ISqlSugarRepository _marketRecordRepository; + private readonly ISqlSugarRepository _marketGoodsRepository; + public BindAccountForCollectiblesEventHandler(InvitationCodeManager invitationCodeManager, ISqlSugarRepository collectiblesUserStoreRepository, ISqlSugarRepository miningPoolRecordRepository, ISqlSugarRepository marketRecordRepository, ISqlSugarRepository marketGoodsRepository) + { + _invitationCodeManager = invitationCodeManager; + _collectiblesUserStoreRepository = collectiblesUserStoreRepository; + _miningPoolRecordRepository = miningPoolRecordRepository; + _marketRecordRepository = marketRecordRepository; + _marketGoodsRepository = marketGoodsRepository; + } + + public async Task HandleEventAsync(BindAccountEto eventData) + { + var oldEntity = await _invitationCodeManager.TryGetOrAddAsync(eventData.OldUserId); + var newEntity = await _invitationCodeManager.TryGetOrAddAsync(eventData.NewUserId); + + newEntity.PointsNumber += oldEntity.PointsNumber; + + //临时账号邀请了,老的账号没有邀请,覆盖 + if (newEntity.IsInvited == false && oldEntity.IsInvited == true) + { + newEntity.IsInvited = true; + } + + await _invitationCodeManager._repository.UpdateAsync(newEntity); + + //藏品转移 + var oldUserStore= await _collectiblesUserStoreRepository.GetListAsync(x => x.UserId == eventData.OldUserId); + if (oldUserStore.Count>0) + { + oldUserStore?.ForEach(x=>x.UserId=eventData.NewUserId); + await _collectiblesUserStoreRepository.UpdateRangeAsync(oldUserStore); + } + + //挖矿记录转移 + var miningPoolRecord= await _miningPoolRecordRepository.GetListAsync(x => x.UserId == eventData.OldUserId); + if (miningPoolRecord.Count>0) + { + miningPoolRecord?.ForEach(x=>x.UserId=eventData.NewUserId); + await _miningPoolRecordRepository.UpdateRangeAsync(miningPoolRecord); + } + + //交易记录转移 + var marketRecord= await _marketRecordRepository.GetListAsync(x => x.SellUserId == eventData.OldUserId||x.BuyId==eventData.OldUserId); + if (marketRecord.Count>0) + { + marketRecord?.ForEach(x => + { + if (x.SellUserId == eventData.OldUserId) + { + x.SellUserId = eventData.NewUserId; + } + + if (x.BuyId == eventData.OldUserId) + { + x.BuyId = eventData.NewUserId; + } + }); + await _marketRecordRepository.UpdateRangeAsync(marketRecord); + } + + + //商城物品交易转移 + var marketGoods= await _marketGoodsRepository.GetListAsync(x => x.SellUserId == eventData.OldUserId); + if (marketGoods.Count>0) + { + marketGoods?.ForEach(x=>x.SellUserId=eventData.NewUserId); + await _marketGoodsRepository.UpdateRangeAsync(marketGoods); + } + } +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Managers/InvitationCodeManager.cs b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Managers/InvitationCodeManager.cs new file mode 100644 index 00000000..4bd436cb --- /dev/null +++ b/Yi.Abp.Net8/module/digital-collectibles/Yi.Framework.DigitalCollectibles.Domain/Managers/InvitationCodeManager.cs @@ -0,0 +1,87 @@ +using Volo.Abp.Domain.Services; +using Yi.Framework.DigitalCollectibles.Domain.Entities; +using Yi.Framework.SqlSugarCore.Abstractions; + +namespace Yi.Framework.DigitalCollectibles.Domain.Managers; + +/// +/// 邀请码领域服务 +/// +public class InvitationCodeManager : DomainService +{ + public readonly ISqlSugarRepository _repository; + + public InvitationCodeManager(ISqlSugarRepository repository) + { + _repository = repository; + } + + + /// + /// 填写邀请码 + /// + public async Task SetAsync(Guid writeUserId, string invitationCode) + { + var entityOrNull = await _repository.GetFirstAsync(x => x.InvitationCode == invitationCode); + if (entityOrNull is null) + { + throw new UserFriendlyException("无效邀请码,请检查"); + } + if (entityOrNull.UserId==writeUserId) + { + throw new UserFriendlyException("你不能邀请自己"); + } + + //被邀请的人 + var entity = entityOrNull; + entity.SetInvited(); + + //填写邀请码的人 + var writeEntity = await TryGetOrAddAsync(writeUserId); + writeEntity.SetInvite(); + + await _repository.UpdateRangeAsync(new List { entity, writeEntity }); + } + + public async Task TryGetOrAddAsync(Guid userId, int InitPointsNumber = 0) + { + var entity = await _repository.FindAsync(x => x.UserId == userId); + if (entity is null) + { + string invitationCode = string.Empty; + + //循环到邀请码没有重复为止 + var isExist = true; + while (isExist) + { + invitationCode = CreateInvitationCode(4); + if (!await _repository.IsAnyAsync(x => x.InvitationCode == invitationCode)) + { + isExist = false; + } + } + + var insertEntity = new InvitationCodeAggregateRoot(userId, invitationCode) + { + PointsNumber = InitPointsNumber + }; + entity = await _repository.InsertReturnEntityAsync(insertEntity); + } + + return entity; + } + + private string CreateInvitationCode(int length) + { + const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + Random random = new Random(); + char[] stringChars = new char[length]; + + for (int i = 0; i < length; i++) + { + stringChars[i] = chars[random.Next(chars.Length)]; + } + + return new string(stringChars); + } +} \ No newline at end of file