diff --git a/.gitignore b/.gitignore index 8ed69463..7bd589c0 100644 --- a/.gitignore +++ b/.gitignore @@ -265,6 +265,7 @@ src/Acme.BookStore.Blazor.Server.Tiered/Logs/* **/wwwroot/libs/* public dist +dist - 副本 .vscode /Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.Development.json /Yi.Abp.Net8/src/Yi.Abp.Web/appsettings.Production.json diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DbConnOptions.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DbConnOptions.cs index 647ca0e8..65c83f13 100644 --- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DbConnOptions.cs +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DbConnOptions.cs @@ -60,8 +60,8 @@ namespace Yi.Framework.SqlSugarCore.Abstractions public bool EnabledSaasMultiTenancy { get; set; } = false; /// - /// 并发乐观锁异常,否则不处理 + /// 是否开启更新并发乐观锁 /// - public bool EnabledConcurrencyException { get; set; } = true; + public bool EnabledConcurrencyException { get;set; } = false; } } \ No newline at end of file diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/Repositories/SqlSugarRepository.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/Repositories/SqlSugarRepository.cs index 1cc1ea61..786254ec 100644 --- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/Repositories/SqlSugarRepository.cs +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/Repositories/SqlSugarRepository.cs @@ -1,12 +1,7 @@ -using System.Linq; using System.Linq.Expressions; -using System.Text; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Nito.AsyncEx; using SqlSugar; -using Volo.Abp; -using Volo.Abp.Auditing; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Entities; @@ -17,18 +12,17 @@ using Yi.Framework.SqlSugarCore.Abstractions; namespace Yi.Framework.SqlSugarCore.Repositories { - public class SqlSugarRepository : ISqlSugarRepository, IRepository - where TEntity : class, IEntity, new() + public class SqlSugarRepository : ISqlSugarRepository, IRepository where TEntity : class, IEntity, new() { public ISqlSugarClient _Db => AsyncContext.Run(async () => await GetDbContextAsync()); public ISugarQueryable _DbQueryable => _Db.Queryable(); private readonly ISugarDbContextProvider _dbContextProvider; - + public IAbpLazyServiceProvider LazyServiceProvider { get; set; } + protected DbConnOptions? Options => LazyServiceProvider?.LazyGetService>().Value; - /// /// 异步查询执行器 /// @@ -64,26 +58,22 @@ namespace Yi.Framework.SqlSugarCore.Repositories #region Abp模块 - public virtual async Task FindAsync(Expression> predicate, - bool includeDetails = true, CancellationToken cancellationToken = default) + public virtual async Task FindAsync(Expression> predicate, bool includeDetails = true, CancellationToken cancellationToken = default) { return await GetFirstAsync(predicate); } - public virtual async Task GetAsync(Expression> predicate, - bool includeDetails = true, CancellationToken cancellationToken = default) + public virtual async Task GetAsync(Expression> predicate, bool includeDetails = true, CancellationToken cancellationToken = default) { return await GetFirstAsync(predicate); } - public virtual async Task DeleteAsync(Expression> predicate, bool autoSave = false, - CancellationToken cancellationToken = default) + public virtual async Task DeleteAsync(Expression> predicate, bool autoSave = false, CancellationToken cancellationToken = default) { await this.DeleteAsync(predicate); } - public virtual async Task DeleteDirectAsync(Expression> predicate, - CancellationToken cancellationToken = default) + public virtual async Task DeleteDirectAsync(Expression> predicate, CancellationToken cancellationToken = default) { await this.DeleteAsync(predicate); } @@ -113,71 +103,60 @@ namespace Yi.Framework.SqlSugarCore.Repositories throw new NotImplementedException(); } - public virtual async Task> GetListAsync(Expression> predicate, - bool includeDetails = false, CancellationToken cancellationToken = default) + public virtual async Task> GetListAsync(Expression> predicate, bool includeDetails = false, CancellationToken cancellationToken = default) { return await GetListAsync(predicate); } - public virtual async Task InsertAsync(TEntity entity, bool autoSave = false, - CancellationToken cancellationToken = default) + public virtual async Task InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { return await InsertReturnEntityAsync(entity); } - public virtual async Task InsertManyAsync(IEnumerable entities, bool autoSave = false, - CancellationToken cancellationToken = default) + public virtual async Task InsertManyAsync(IEnumerable entities, bool autoSave = false, CancellationToken cancellationToken = default) { await InsertRangeAsync(entities.ToList()); } - public virtual async Task UpdateAsync(TEntity entity, bool autoSave = false, - CancellationToken cancellationToken = default) + public virtual async Task UpdateAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { await UpdateAsync(entity); return entity; } - public virtual async Task UpdateManyAsync(IEnumerable entities, bool autoSave = false, - CancellationToken cancellationToken = default) + public virtual async Task UpdateManyAsync(IEnumerable entities, bool autoSave = false, CancellationToken cancellationToken = default) { await UpdateRangeAsync(entities.ToList()); } - public virtual async Task DeleteAsync(TEntity entity, bool autoSave = false, - CancellationToken cancellationToken = default) + public virtual async Task DeleteAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) { await DeleteAsync(entity); } - public virtual async Task DeleteManyAsync(IEnumerable entities, bool autoSave = false, - CancellationToken cancellationToken = default) + public virtual async Task DeleteManyAsync(IEnumerable entities, bool autoSave = false, CancellationToken cancellationToken = default) { await DeleteAsync(entities.ToList()); } - public virtual async Task> GetListAsync(bool includeDetails = false, - CancellationToken cancellationToken = default) + public virtual async Task> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default) { return await GetListAsync(); } public virtual async Task GetCountAsync(CancellationToken cancellationToken = default) { - return await this.CountAsync(_ => true); + return await this.CountAsync(_=>true); } - public virtual async Task> GetPagedListAsync(int skipCount, int maxResultCount, string sorting, - bool includeDetails = false, CancellationToken cancellationToken = default) + public virtual async Task> GetPagedListAsync(int skipCount, int maxResultCount, string sorting, bool includeDetails = false, CancellationToken cancellationToken = default) { return await GetPageListAsync(_ => true, skipCount, maxResultCount); } - #endregion #region 内置DB快捷操作 - public virtual async Task> AsDeleteable() { return (await GetDbSimpleClientAsync()).AsDeleteable(); @@ -192,7 +171,7 @@ namespace Yi.Framework.SqlSugarCore.Repositories { return (await GetDbSimpleClientAsync()).AsInsertable(insertObj); } - + public virtual async Task> AsInsertable(TEntity[] insertObjs) { return (await GetDbSimpleClientAsync()).AsInsertable(insertObjs); @@ -232,11 +211,9 @@ namespace Yi.Framework.SqlSugarCore.Repositories { return (await GetDbSimpleClientAsync()).AsUpdateable(updateObjs); } - #endregion #region SimpleClient模块 - public virtual async Task CountAsync(Expression> whereExpression) { return await (await GetDbSimpleClientAsync()).CountAsync(whereExpression); @@ -253,6 +230,7 @@ namespace Yi.Framework.SqlSugarCore.Repositories { return await (await GetDbSimpleClientAsync()).DeleteAsync(deleteObj); } + } public virtual async Task DeleteAsync(List deleteObjs) @@ -272,13 +250,13 @@ namespace Yi.Framework.SqlSugarCore.Repositories { if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity))) { - return await (await GetDbSimpleClientAsync()).AsUpdateable() - .SetColumns(nameof(ISoftDelete.IsDeleted), true).Where(whereExpression).ExecuteCommandAsync() > 0; + return await (await GetDbSimpleClientAsync()).AsUpdateable().SetColumns(nameof(ISoftDelete.IsDeleted), true).Where(whereExpression).ExecuteCommandAsync() > 0; } else { return await (await GetDbSimpleClientAsync()).DeleteAsync(whereExpression); } + } public virtual async Task DeleteByIdAsync(dynamic id) @@ -286,11 +264,7 @@ namespace Yi.Framework.SqlSugarCore.Repositories if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity))) { var entity = await GetByIdAsync(id); - if (entity is null) - { - return false; - } - + if (entity == null) return false; //反射赋值 ReflexHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, entity); return await UpdateAsync(entity); @@ -311,7 +285,6 @@ namespace Yi.Framework.SqlSugarCore.Repositories { return false; } - //反射赋值 entities.ForEach(e => ReflexHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, e)); return await UpdateRangeAsync(entities); @@ -320,6 +293,7 @@ namespace Yi.Framework.SqlSugarCore.Repositories { return await (await GetDbSimpleClientAsync()).DeleteByIdAsync(ids); } + } public virtual async Task GetByIdAsync(dynamic id) @@ -328,6 +302,7 @@ namespace Yi.Framework.SqlSugarCore.Repositories } + public virtual async Task GetFirstAsync(Expression> whereExpression) { return await (await GetDbSimpleClientAsync()).GetFirstAsync(whereExpression); @@ -343,19 +318,14 @@ namespace Yi.Framework.SqlSugarCore.Repositories return await (await GetDbSimpleClientAsync()).GetListAsync(whereExpression); } - public virtual async Task> GetPageListAsync(Expression> whereExpression, - int pageNum, int pageSize) + public virtual async Task> GetPageListAsync(Expression> whereExpression, int pageNum, int pageSize) { - return await (await GetDbSimpleClientAsync()).GetPageListAsync(whereExpression, - new PageModel() { PageIndex = pageNum, PageSize = pageSize }); + return await (await GetDbSimpleClientAsync()).GetPageListAsync(whereExpression, new PageModel() { PageIndex = pageNum, PageSize = pageSize }); } - public virtual async Task> GetPageListAsync(Expression> whereExpression, - int pageNum, int pageSize, Expression>? orderByExpression = null, - OrderByType orderByType = OrderByType.Asc) + public virtual async Task> GetPageListAsync(Expression> whereExpression, int pageNum, int pageSize, Expression>? orderByExpression = null, OrderByType orderByType = OrderByType.Asc) { - return await (await GetDbSimpleClientAsync()).GetPageListAsync(whereExpression, - new PageModel { PageIndex = pageNum, PageSize = pageSize }, orderByExpression, orderByType); + return await (await GetDbSimpleClientAsync()).GetPageListAsync(whereExpression, new PageModel { PageIndex = pageNum, PageSize = pageSize }, orderByExpression, orderByType); } public virtual async Task GetSingleAsync(Expression> whereExpression) @@ -410,9 +380,9 @@ namespace Yi.Framework.SqlSugarCore.Repositories public virtual async Task UpdateAsync(TEntity updateObj) { - if (typeof(TEntity).IsAssignableTo()) //带版本号乐观锁更新 + if (Options is not null && Options.EnabledConcurrencyException) { - if (Options is not null && Options.EnabledConcurrencyException) + if (typeof(TEntity).IsAssignableTo()) //带版本号乐观锁更新 { try { @@ -426,24 +396,18 @@ namespace Yi.Framework.SqlSugarCore.Repositories $"{ex.Message}[更新失败:ConcurrencyStamp不是最新版本],entityInfo:{updateObj}", ex); } } - else - { - int num = await (await GetDbSimpleClientAsync()) - .Context.Updateable(updateObj).ExecuteCommandAsync(); - return num > 0; - } } return await (await GetDbSimpleClientAsync()).UpdateAsync(updateObj); } - public virtual async Task UpdateAsync(Expression> columns, - Expression> whereExpression) + public virtual async Task UpdateAsync(Expression> columns, Expression> whereExpression) { return await (await GetDbSimpleClientAsync()).UpdateAsync(columns, whereExpression); } + public virtual async Task UpdateRangeAsync(List updateObjs) { return await (await GetDbSimpleClientAsync()).UpdateRangeAsync(updateObjs); @@ -452,36 +416,30 @@ namespace Yi.Framework.SqlSugarCore.Repositories #endregion } - public class SqlSugarRepository : SqlSugarRepository, ISqlSugarRepository, - IRepository where TEntity : class, IEntity, new() + public class SqlSugarRepository : SqlSugarRepository, ISqlSugarRepository, IRepository where TEntity : class, IEntity, new() { - public SqlSugarRepository(ISugarDbContextProvider dbContextProvider) : base( - dbContextProvider) + public SqlSugarRepository(ISugarDbContextProvider sugarDbContextProvider) : base(sugarDbContextProvider) { } - public virtual async Task DeleteAsync(TKey id, bool autoSave = false, - CancellationToken cancellationToken = default) + public virtual async Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default) { await DeleteByIdAsync(id); } - public virtual async Task DeleteManyAsync(IEnumerable ids, bool autoSave = false, - CancellationToken cancellationToken = default) + public virtual async Task DeleteManyAsync(IEnumerable ids, bool autoSave = false, CancellationToken cancellationToken = default) { await DeleteByIdsAsync(ids.Select(x => (object)x).ToArray()); } - public virtual async Task FindAsync(TKey id, bool includeDetails = true, - CancellationToken cancellationToken = default) + public virtual async Task FindAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) { return await GetByIdAsync(id); } - public virtual async Task GetAsync(TKey id, bool includeDetails = true, - CancellationToken cancellationToken = default) + public virtual async Task GetAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) { return await GetByIdAsync(id); } } -} \ No newline at end of file +} diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Announcement/AnnouncementCacheDto.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Announcement/AnnouncementCacheDto.cs index 5b8cd6c7..b1e1e30c 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Announcement/AnnouncementCacheDto.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Announcement/AnnouncementCacheDto.cs @@ -14,4 +14,9 @@ public class AnnouncementCacheDto /// 公告日志列表 /// public List Logs { get; set; } = new List(); + + /// + /// 跳转链接 + /// + public string? Url { get; set; } } diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Announcement/AnnouncementLogDto.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Announcement/AnnouncementLogDto.cs index 0a7ef430..6014896c 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Announcement/AnnouncementLogDto.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Announcement/AnnouncementLogDto.cs @@ -1,3 +1,5 @@ +using Yi.Framework.AiHub.Domain.Shared.Enums; + namespace Yi.Framework.AiHub.Application.Contracts.Dtos.Announcement; /// @@ -5,18 +7,38 @@ namespace Yi.Framework.AiHub.Application.Contracts.Dtos.Announcement; /// public class AnnouncementLogDto { - /// - /// 日期 - /// - public string Date { get; set; } = string.Empty; - /// /// 标题 /// - public string Title { get; set; } = string.Empty; + public string Title { get; set; } /// /// 内容列表 /// public List Content { get; set; } = new List(); + + /// + /// 图片url + /// + public string? ImageUrl { get; set; } + + /// + /// 开始时间(系统公告时间、活动开始时间) + /// + public DateTime StartTime { get; set; } + + /// + /// 活动结束时间 + /// + public DateTime? EndTime { get; set; } + + /// + /// 公告类型(系统、活动) + /// + public AnnouncementTypeEnum Type{ get; set; } + + /// + /// 跳转链接 + /// + public string? Url { get; set; } } diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/CardFlip/CardFlipStatusOutput.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/CardFlip/CardFlipStatusOutput.cs index 3594dbb8..082c20f9 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/CardFlip/CardFlipStatusOutput.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/CardFlip/CardFlipStatusOutput.cs @@ -39,12 +39,7 @@ public class CardFlipStatusOutput /// 本周邀请人数 /// public int InvitedCount { get; set; } - - /// - /// 是否已被邀请(被邀请后不可再提供邀请码) - /// - public bool IsInvited { get; set; } - + /// /// 翻牌记录 /// @@ -54,6 +49,11 @@ public class CardFlipStatusOutput /// 下次可翻牌提示 /// public string? NextFlipTip { get; set; } + + /// + /// 当前用户是否已经填写过邀请码 + /// + public bool IsFilledInviteCode { get; set; } } /// diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/UsageStatistics/PremiumTokenUsageGetListInput.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/UsageStatistics/PremiumTokenUsageGetListInput.cs new file mode 100644 index 00000000..e3766e10 --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/UsageStatistics/PremiumTokenUsageGetListInput.cs @@ -0,0 +1,12 @@ +using Volo.Abp.Application.Dtos; +using Yi.Framework.Ddd.Application.Contracts; + +namespace Yi.Framework.AiHub.Application.Contracts.Dtos.UsageStatistics; + +public class PremiumTokenUsageGetListInput : PagedAllResultRequestDto +{ + /// + /// 是否免费 + /// + public bool? IsFree { get; set; } +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/UsageStatistics/PremiumTokenUsageGetListOutput.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/UsageStatistics/PremiumTokenUsageGetListOutput.cs new file mode 100644 index 00000000..d3b29ffc --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/UsageStatistics/PremiumTokenUsageGetListOutput.cs @@ -0,0 +1,57 @@ +using Volo.Abp.Application.Dtos; +using Yi.Framework.Ddd.Application.Contracts; + +namespace Yi.Framework.AiHub.Application.Contracts.Dtos.UsageStatistics; + +public class PremiumTokenUsageGetListOutput : CreationAuditedEntityDto +{ + /// + /// id + /// + public Guid Id { get; set; } + + /// + /// 用户ID + /// + public Guid UserId { get; set; } + + /// + /// 包名称 + /// + public string PackageName { get; set; } + + /// + /// 总用量(总token数) + /// + public long TotalTokens { get; set; } + + /// + /// 剩余用量(剩余token数) + /// + public long RemainingTokens { get; set; } + + /// + /// 已使用token数 + /// + public long UsedTokens { get; set; } + + /// + /// 到期时间 + /// + public DateTime? ExpireDateTime { get; set; } + + /// + /// 是否激活 + /// + public bool IsActive { get; set; } + + /// + /// 购买金额 + /// + public decimal PurchaseAmount { get; set; } + + /// + /// 备注 + /// + public string? Remark { get; set; } +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/IServices/IAnnouncementService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/IServices/IAnnouncementService.cs index 77d4d29a..acdda549 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/IServices/IAnnouncementService.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/IServices/IAnnouncementService.cs @@ -11,5 +11,5 @@ public interface IAnnouncementService /// 获取公告信息 /// /// 公告信息 - Task GetAsync(); + Task> GetAsync(); } diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/AnnouncementService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/AnnouncementService.cs index 8914cd25..2399070e 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/AnnouncementService.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/AnnouncementService.cs @@ -1,3 +1,4 @@ +using Mapster; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Configuration; using Volo.Abp.Application.Services; @@ -14,13 +15,13 @@ namespace Yi.Framework.AiHub.Application.Services; /// public class AnnouncementService : ApplicationService, IAnnouncementService { - private readonly ISqlSugarRepository _announcementRepository; + private readonly ISqlSugarRepository _announcementRepository; private readonly IConfiguration _configuration; private readonly IDistributedCache _announcementCache; private const string AnnouncementCacheKey = "AiHub:Announcement"; public AnnouncementService( - ISqlSugarRepository announcementRepository, + ISqlSugarRepository announcementRepository, IConfiguration configuration, IDistributedCache announcementCache) { @@ -32,7 +33,7 @@ public class AnnouncementService : ApplicationService, IAnnouncementService /// /// 获取公告信息 /// - public async Task GetAsync() + public async Task> GetAsync() { // 使用 GetOrAddAsync 从缓存获取或添加数据,缓存1小时 var cacheData = await _announcementCache.GetOrAddAsync( @@ -44,11 +45,7 @@ public class AnnouncementService : ApplicationService, IAnnouncementService } ); - return new AnnouncementOutput - { - Version = cacheData?.Version ?? "v1.0.0", - Logs = cacheData?.Logs ?? new List() - }; + return cacheData?.Logs ?? new List(); } /// @@ -56,25 +53,15 @@ public class AnnouncementService : ApplicationService, IAnnouncementService /// private async Task LoadAnnouncementDataAsync() { - // 从配置文件读取版本号,如果没有配置则使用默认值 - var version = _configuration["AiHubVersion"] ?? "v1.0.0"; - // 查询所有公告日志,按日期降序排列 var logs = await _announcementRepository._DbQueryable - .OrderByDescending(x => x.Date) + .OrderByDescending(x => x.StartTime) .ToListAsync(); // 转换为 DTO - var logDtos = logs.Select(log => new AnnouncementLogDto - { - Date = log.Date.ToString("yyyy-MM-dd"), - Title = log.Title, - Content = log.Content - }).ToList(); - + var logDtos = logs.Adapt>(); return new AnnouncementCacheDto { - Version = version, Logs = logDtos }; } diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/CardFlipService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/CardFlipService.cs index d7bb6ba8..feefd4ba 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/CardFlipService.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/CardFlipService.cs @@ -51,9 +51,8 @@ public class CardFlipService : ApplicationService, ICardFlipService // 统计本周邀请人数 var invitedCount = await _inviteCodeManager.GetWeeklyInvitationCountAsync(userId, weekStart); - // 检查用户是否已被邀请 - var isInvited = await _inviteCodeManager.IsUserInvitedAsync(userId); - + //当前用户是否已填写过邀请码 + var isFilledInviteCode = await _inviteCodeManager.IsFilledInviteCodeAsync(userId); var output = new CardFlipStatusOutput { TotalFlips = task?.TotalFlips ?? 0, @@ -63,8 +62,8 @@ public class CardFlipService : ApplicationService, ICardFlipService CanFlip = _cardFlipManager.CanFlipCard(task), MyInviteCode = inviteCode?.Code, InvitedCount = invitedCount, - IsInvited = isInvited, - FlipRecords = BuildFlipRecords(task) + FlipRecords = BuildFlipRecords(task), + IsFilledInviteCode = isFilledInviteCode }; // 生成提示信息 @@ -87,7 +86,7 @@ public class CardFlipService : ApplicationService, ICardFlipService // 如果中奖,发放奖励 if (result.IsWin) { - await GrantRewardAsync(userId, result.RewardAmount, $"翻牌活动第{input.FlipNumber}次中奖"); + await GrantRewardAsync(userId, result.RewardAmount, $"翻牌活动-序号{input.FlipNumber}中奖"); } // 构建输出 @@ -147,7 +146,6 @@ public class CardFlipService : ApplicationService, ICardFlipService { MyInviteCode = inviteCode?.Code, InvitedCount = invitedCount, - IsInvited = inviteCode?.IsUserInvited ?? false, InvitationHistory = invitationHistory.Select(x => new InvitationHistoryItem { InvitedUserName = x.InvitedUserName, @@ -183,6 +181,9 @@ public class CardFlipService : ApplicationService, ICardFlipService var flippedOrder = task != null ? _cardFlipManager.GetFlippedOrder(task) : new List(); var flippedNumbers = new HashSet(flippedOrder); + // 获取中奖记录 + var winRecords = task?.WinRecords ?? new Dictionary(); + // 构建记录,按照原始序号1-10排列 for (int i = 1; i <= CardFlipManager.TOTAL_MAX_FLIPS; i++) { @@ -202,23 +203,11 @@ public class CardFlipService : ApplicationService, ICardFlipService { var flipOrderIndex = flippedOrder.IndexOf(i) + 1; // 第几次翻的(1-based) - // 第8次翻的卡中奖 - if (flipOrderIndex == 8) + // 检查这次翻牌是否中奖 + if (winRecords.TryGetValue(flipOrderIndex, out var rewardAmount)) { record.IsWin = true; - record.RewardAmount = task.EighthRewardAmount; - } - // 第9次翻的卡中奖 - else if (flipOrderIndex == 9) - { - record.IsWin = true; - record.RewardAmount = task.NinthRewardAmount; - } - // 第10次翻的卡中奖 - else if (flipOrderIndex == 10) - { - record.IsWin = true; - record.RewardAmount = task.TenthRewardAmount; + record.RewardAmount = rewardAmount; } } @@ -246,10 +235,10 @@ public class CardFlipService : ApplicationService, ICardFlipService { if (status.TotalFlips >= 7) { - return $"本周使用他人邀请码可解锁{status.RemainingInviteFlips}次翻牌,且必中大奖!每次中奖最大额度将翻倍!"; + return $"本周使用他人邀请码或他人使用你的邀请码,可解锁{status.RemainingInviteFlips}次翻牌,且必中大奖!每次中奖最大额度将翻倍!"; } - return $"本周使用他人邀请码可解锁{status.RemainingInviteFlips}次翻牌,必中大奖!每次中奖最大额度将翻倍!"; + return $"本周使用他人邀请码或他人使用你的邀请码,可解锁{status.RemainingInviteFlips}次翻牌,必中大奖!每次中奖最大额度将翻倍!"; } return "继续加油!"; diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/AiChatService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/Chat/AiChatService.cs similarity index 100% rename from Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/AiChatService.cs rename to Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/Chat/AiChatService.cs diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/MessageService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/Chat/MessageService.cs similarity index 100% rename from Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/MessageService.cs rename to Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/Chat/MessageService.cs diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/SessionService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/Chat/SessionService.cs similarity index 100% rename from Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/SessionService.cs rename to Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/Chat/SessionService.cs diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/TokenService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/Chat/TokenService.cs similarity index 100% rename from Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/TokenService.cs rename to Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/Chat/TokenService.cs diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/UsageStatisticsService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/UsageStatisticsService.cs index 05d6eaeb..feedf690 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/UsageStatisticsService.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/UsageStatisticsService.cs @@ -1,5 +1,8 @@ +using Mapster; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using SqlSugar; +using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Services; using Volo.Abp.Users; using Yi.Framework.AiHub.Application.Contracts.Dtos.UsageStatistics; @@ -7,6 +10,7 @@ using Yi.Framework.AiHub.Application.Contracts.IServices; using Yi.Framework.AiHub.Domain.Entities; using Yi.Framework.AiHub.Domain.Entities.Chat; using Yi.Framework.AiHub.Domain.Extensions; +using Yi.Framework.Ddd.Application.Contracts; using Yi.Framework.SqlSugarCore.Abstractions; namespace Yi.Framework.AiHub.Application.Services; @@ -137,4 +141,27 @@ public class UsageStatisticsService : ApplicationService, IUsageStatisticsServic return result; } + + /// + /// 获取当前用户尊享服务token用量统计列表 + /// + /// + [HttpGet("usage-statistics/premium-token-usage/list")] + public async Task> GetPremiumTokenUsageListAsync( + PremiumTokenUsageGetListInput input) + { + var userId = CurrentUser.GetId(); + RefAsync total = 0; + // 获取尊享包Token信息 + var entities = await _premiumPackageRepository._DbQueryable + .Where(x => x.UserId == userId) + .WhereIF(input.IsFree == false, x => x.PurchaseAmount > 0) + .WhereIF(input.IsFree == true, x => x.PurchaseAmount == 0) + .WhereIF(input.StartTime is not null && input.EndTime is not null, + x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime) + .OrderByDescending(x => x.CreationTime) + .ToPageListAsync(input.SkipCount, input.MaxResultCount, total); + return new PagedResultDto(total, + entities.Adapt>()); + } } \ No newline at end of file diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/AnnouncementTypeEnum.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/AnnouncementTypeEnum.cs new file mode 100644 index 00000000..fa898e18 --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/AnnouncementTypeEnum.cs @@ -0,0 +1,7 @@ +namespace Yi.Framework.AiHub.Domain.Shared.Enums; + +public enum AnnouncementTypeEnum +{ + Activity=1, + System=2 +} \ No newline at end of file diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/AnnouncementAggregateRoot.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/AnnouncementAggregateRoot.cs new file mode 100644 index 00000000..4488d985 --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/AnnouncementAggregateRoot.cs @@ -0,0 +1,57 @@ +using SqlSugar; +using Volo.Abp.Domain.Entities.Auditing; +using Yi.Framework.AiHub.Domain.Shared.Enums; + +namespace Yi.Framework.AiHub.Domain.Entities; + +/// +/// 公告日志 +/// +[SugarTable("Ai_Announcement")] +public class AnnouncementAggregateRoot : FullAuditedAggregateRoot +{ + public AnnouncementAggregateRoot() + { + } + + /// + /// 标题 + /// + public string Title { get; set; } = string.Empty; + + /// + /// 内容列表(JSON格式存储) + /// + [SugarColumn(IsJson = true, IsNullable = false)] + public List Content { get; set; } = new List(); + + /// + /// 备注 + /// + public string? Remark { get; set; } + + /// + /// 图片url + /// + public string? ImageUrl { get; set; } + + /// + /// 开始时间(系统公告时间、活动开始时间) + /// + public DateTime StartTime { get; set; } + + /// + /// 活动结束时间 + /// + public DateTime? EndTime { get; set; } + + /// + /// 公告类型(系统、活动) + /// + public AnnouncementTypeEnum Type{ get; set; } + + /// + /// 跳转链接 + /// + public string? Url { get; set; } +} diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/AnnouncementLogAggregateRoot.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/AnnouncementLogAggregateRoot.cs deleted file mode 100644 index ec890394..00000000 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/AnnouncementLogAggregateRoot.cs +++ /dev/null @@ -1,44 +0,0 @@ -using SqlSugar; -using Volo.Abp.Domain.Entities.Auditing; - -namespace Yi.Framework.AiHub.Domain.Entities; - -/// -/// 公告日志 -/// -[SugarTable("Ai_AnnouncementLog")] -[SugarIndex($"index_{nameof(Date)}", nameof(Date), OrderByType.Desc)] -public class AnnouncementLogAggregateRoot : FullAuditedAggregateRoot -{ - public AnnouncementLogAggregateRoot() - { - } - - public AnnouncementLogAggregateRoot(DateTime date, string title, List content) - { - Date = date; - Title = title; - Content = content; - } - - /// - /// 日期 - /// - public DateTime Date { get; set; } - - /// - /// 标题 - /// - public string Title { get; set; } = string.Empty; - - /// - /// 内容列表(JSON格式存储) - /// - [SugarColumn(IsJson = true, IsNullable = false)] - public List Content { get; set; } = new List(); - - /// - /// 备注 - /// - public string? Remark { get; set; } -} diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/CardFlipTaskAggregateRoot.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/CardFlipTaskAggregateRoot.cs index 3adaba7e..9f51870e 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/CardFlipTaskAggregateRoot.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/CardFlipTaskAggregateRoot.cs @@ -25,9 +25,8 @@ public class CardFlipTaskAggregateRoot : FullAuditedAggregateRoot BonusFlipsUsed = 0; InviteFlipsUsed = 0; IsFirstFlipDone = false; - HasNinthReward = false; - HasTenthReward = false; FlippedOrder = new List(); + WinRecords = new Dictionary(); } /// @@ -66,34 +65,10 @@ public class CardFlipTaskAggregateRoot : FullAuditedAggregateRoot public bool IsFirstFlipDone { get; set; } /// - /// 是否已获得第8次奖励 + /// 中奖记录(以翻牌顺序为key,例如第1次翻牌中奖则key为1,奖励金额为value) /// - public bool HasEighthReward { get; set; } - - /// - /// 第8次奖励金额(100-300w) - /// - public long? EighthRewardAmount { get; set; } - - /// - /// 是否已获得第9次奖励 - /// - public bool HasNinthReward { get; set; } - - /// - /// 第9次奖励金额(100-500w) - /// - public long? NinthRewardAmount { get; set; } - - /// - /// 是否已获得第10次奖励 - /// - public bool HasTenthReward { get; set; } - - /// - /// 第10次奖励金额(100-1000w) - /// - public long? TenthRewardAmount { get; set; } + [SugarColumn(IsJson = true, IsNullable = true)] + public Dictionary? WinRecords { get; set; } /// /// 备注信息 @@ -135,33 +110,17 @@ public class CardFlipTaskAggregateRoot : FullAuditedAggregateRoot } /// - /// 记录第8次奖励 + /// 记录中奖 /// + /// 第几次翻牌(1-10) /// 奖励金额 - public void SetEighthReward(long amount) + public void SetWinReward(int flipCount, long amount) { - HasEighthReward = true; - EighthRewardAmount = amount; - } - - /// - /// 记录第9次奖励 - /// - /// 奖励金额 - public void SetNinthReward(long amount) - { - HasNinthReward = true; - NinthRewardAmount = amount; - } - - /// - /// 记录第10次奖励 - /// - /// 奖励金额 - public void SetTenthReward(long amount) - { - HasTenthReward = true; - TenthRewardAmount = amount; + if (WinRecords == null) + { + WinRecords = new Dictionary(); + } + WinRecords[flipCount] = amount; } } diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/InviteCodeAggregateRoot.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/InviteCodeAggregateRoot.cs index de569b49..bcd310af 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/InviteCodeAggregateRoot.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/InviteCodeAggregateRoot.cs @@ -19,8 +19,6 @@ public class InviteCodeAggregateRoot : FullAuditedAggregateRoot { UserId = userId; Code = code; - IsUsed = false; - IsUserInvited = false; UsedCount = 0; } @@ -34,55 +32,16 @@ public class InviteCodeAggregateRoot : FullAuditedAggregateRoot /// [SugarColumn(Length = 50)] public string Code { get; set; } = string.Empty; - + /// - /// 是否已被使用(一个邀请码只能被使用一次) - /// - public bool IsUsed { get; set; } - - /// - /// 邀请码拥有者是否已被他人邀请(被邀请后不可再提供邀请码) - /// - public bool IsUserInvited { get; set; } - - /// - /// 被使用次数(统计用) + /// 被使用次数(统计用,一个邀请码可以被多人使用) /// public int UsedCount { get; set; } - /// - /// 使用时间 - /// - public DateTime? UsedTime { get; set; } - - /// - /// 使用人ID - /// - public Guid? UsedByUserId { get; set; } - /// /// 备注信息 /// [SugarColumn(Length = 500, IsNullable = true)] public string? Remark { get; set; } - - /// - /// 标记邀请码已被使用 - /// - /// 使用者ID - public void MarkAsUsed(Guid usedByUserId) - { - IsUsed = true; - UsedTime = DateTime.Now; - UsedByUserId = usedByUserId; - UsedCount++; - } - - /// - /// 标记用户已被邀请 - /// - public void MarkUserAsInvited() - { - IsUserInvited = true; - } + } diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/CardFlipManager.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/CardFlipManager.cs index 0eae034c..96ae5d1d 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/CardFlipManager.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/CardFlipManager.cs @@ -24,6 +24,11 @@ public class CardFlipManager : DomainService private const int NINTH_FLIP = 9; // 第9次翻牌 private const int TENTH_FLIP = 10; // 第10次翻牌 + // 前7次免费翻牌奖励配置 + private const long FREE_MIN_REWARD = 10000; // 前7次最小奖励 1w + private const long FREE_MAX_REWARD = 30000; // 前7次最大奖励 3w + private const double FREE_WIN_RATE = 0.5; // 前7次中奖概率 50% + private const long EIGHTH_MIN_REWARD = 1000000; // 第8次最小奖励 100w private const long EIGHTH_MAX_REWARD = 3000000; // 第8次最大奖励 300w private const long NINTH_MIN_REWARD = 1000000; // 第9次最小奖励 100w @@ -112,23 +117,23 @@ public class CardFlipManager : DomainService throw new UserFriendlyException(GetFlipTypeErrorMessage(flipType)); } - // 如果是邀请类型翻牌,必须验证用户本周填写的邀请码数量足够 + // 如果是邀请类型翻牌,必须验证用户本周的邀请记录数量足够(包括填写别人的邀请码和别人填写我的邀请码) if (flipType == FlipType.Invite) { - // 查询本周已使用的邀请码数量 - var weeklyInviteCodeUsedCount = await _invitationRecordRepository._DbQueryable - .Where(x => x.InvitedUserId == userId) + // 查询本周作为邀请人或被邀请人的记录数量(双方都会增加翻牌次数) + var weeklyInviteRecordCount = await _invitationRecordRepository._DbQueryable + .Where(x => x.InviterId == userId || x.InvitedUserId == userId) .Where(x => x.InvitationTime >= weekStart) .CountAsync(); - // 本周填写的邀请码数量必须 >= 即将使用的邀请翻牌次数 - // 例如: 要翻第8次(InviteFlipsUsed=0->1), 需要至少填写了1个邀请码 - // 要翻第9次(InviteFlipsUsed=1->2), 需要至少填写了2个邀请码 - // 要翻第10次(InviteFlipsUsed=2->3), 需要至少填写了3个邀请码 - var requiredInviteCodeCount = task.InviteFlipsUsed + 1; - if (weeklyInviteCodeUsedCount < requiredInviteCodeCount) + // 本周邀请记录数量必须 >= 即将使用的邀请翻牌次数 + // 例如: 要翻第8次(InviteFlipsUsed=0->1), 需要至少有1条邀请记录(我邀请别人或别人邀请我) + // 要翻第9次(InviteFlipsUsed=1->2), 需要至少有2条邀请记录 + // 要翻第10次(InviteFlipsUsed=2->3), 需要至少有3条邀请记录 + var requiredInviteRecordCount = task.InviteFlipsUsed + 1; + if (weeklyInviteRecordCount < requiredInviteRecordCount) { - throw new UserFriendlyException($"需本周累积使用{requiredInviteCodeCount}个他人邀请码才能解锁第{task.TotalFlips + 1}次翻牌,您还差一个~"); + throw new UserFriendlyException($"需本周累积{requiredInviteRecordCount}次邀请记录(填写别人的邀请码或别人填写你的邀请码)才能解锁第{task.TotalFlips + 1}次翻牌"); } } @@ -152,18 +157,7 @@ public class CardFlipManager : DomainService // 如果中奖,记录奖励金额(用于后续查询显示) if (result.IsWin) { - if (flipCount == EIGHTH_FLIP) - { - task.SetEighthReward(result.RewardAmount); - } - else if (flipCount == NINTH_FLIP) - { - task.SetNinthReward(result.RewardAmount); - } - else if (flipCount == TENTH_FLIP) - { - task.SetTenthReward(result.RewardAmount); - } + task.SetWinReward(flipCount, result.RewardAmount); } await _cardFlipTaskRepository.UpdateAsync(task); @@ -223,11 +217,24 @@ public class CardFlipManager : DomainService IsWin = false }; - // 前7次固定失败 + var random = new Random(); + + // 前7次: 50%概率中奖,奖励1w-3w if (flipCount <= 7) { - result.IsWin = false; - result.RewardDesc = "很遗憾,未中奖"; + // 50%概率中奖 + if (random.NextDouble() < FREE_WIN_RATE) + { + var rewardAmount = GenerateRandomReward(FREE_MIN_REWARD, FREE_MAX_REWARD); + result.IsWin = true; + result.RewardAmount = rewardAmount; + result.RewardDesc = $"恭喜获得尊享包 {rewardAmount / 10000m:0.##}w tokens!"; + } + else + { + result.IsWin = false; + result.RewardDesc = "很遗憾,未中奖"; + } } // 第8次中奖 (邀请码解锁) else if (flipCount == EIGHTH_FLIP) @@ -271,21 +278,24 @@ public class CardFlipManager : DomainService } /// - /// 生成随机奖励金额 (最小单位100w) + /// 生成随机奖励金额 /// private long GenerateRandomReward(long min, long max) { var random = new Random(); - const long unit = 1000000; // 100w的单位 - // 将min和max转换为100w的倍数 + // 根据最小值判断单位 + // 如果min小于100000,则使用1w(10000)作为单位;否则使用100w(1000000)作为单位 + long unit = min < 100000 ? 10000 : 1000000; + + // 将min和max转换为单位的倍数 long minUnits = min / unit; long maxUnits = max / unit; // 在倍数范围内随机 long randomUnits = random.Next((int)minUnits, (int)maxUnits + 1); - // 返回100w的倍数 + // 返回单位的倍数 return randomUnits * unit; } diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/InviteCodeManager.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/InviteCodeManager.cs index 1deed773..9fae5e81 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/InviteCodeManager.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/InviteCodeManager.cs @@ -63,14 +63,19 @@ public class InviteCodeManager : DomainService } /// - /// 统计用户本周邀请人数 + /// 统计用户本周邀请人数(别人填写我的邀请码的次数/或者我填写别人邀请码) /// public async Task GetWeeklyInvitationCountAsync(Guid userId, DateTime weekStart) { - return await _invitationRecordRepository._DbQueryable + var inviterCount= await _invitationRecordRepository._DbQueryable + .Where(x => x.InviterId == userId) + .Where(x => x.InvitationTime >= weekStart) + .CountAsync(); + var invitedUserIdCount= await _invitationRecordRepository._DbQueryable .Where(x => x.InvitedUserId == userId) .Where(x => x.InvitationTime >= weekStart) .CountAsync(); + return inviterCount + invitedUserIdCount; } /// @@ -91,7 +96,7 @@ public class InviteCodeManager : DomainService } /// - /// 使用邀请码 + /// 使用邀请码(双方都增加翻牌次数) /// /// 使用者ID /// 邀请码 @@ -118,75 +123,40 @@ public class InviteCodeManager : DomainService { throw new UserFriendlyException("不能使用自己的邀请码"); } + + // 检查当前用户是否已经填写过别人的邀请码(一辈子只能填写一次) + var hasUsedOthersCode = await IsFilledInviteCodeAsync(userId); - // 验证邀请码是否已被使用 - if (inviteCodeEntity.IsUsed) + if (hasUsedOthersCode) { - throw new UserFriendlyException("该邀请码已被使用"); + throw new UserFriendlyException("您已经填写过别人的邀请码了,每个账号只能填写一次"); } - - // 验证邀请码拥有者是否已被邀请 - if (inviteCodeEntity.IsUserInvited) - { - throw new UserFriendlyException("该用户已被邀请,邀请码无效"); - } - - // 验证本周邀请码使用次数 - var weekStart = CardFlipManager.GetWeekStartDate(DateTime.Now); - var weeklyUseCount = await _invitationRecordRepository._DbQueryable - .Where(x => x.InvitedUserId == userId) - .Where(x => x.InvitationTime >= weekStart) - .CountAsync(); - - if (weeklyUseCount >= CardFlipManager.MAX_INVITE_FLIPS) - { - throw new UserFriendlyException($"本周邀请码使用次数已达上限({CardFlipManager.MAX_INVITE_FLIPS}次),请下周再来"); - } - - // 检查当前用户的邀请码信息 - var myInviteCode = await _inviteCodeRepository._DbQueryable - .Where(x => x.UserId == userId) - .FirstAsync(); - - // 标记邀请码为已使用 - inviteCodeEntity.MarkAsUsed(userId); + + // 增加邀请码被使用次数 + inviteCodeEntity.UsedCount++; await _inviteCodeRepository.UpdateAsync(inviteCodeEntity); - - // 标记当前用户已被邀请(仅第一次使用邀请码时标记) - if (myInviteCode == null) - { - myInviteCode = new InviteCodeAggregateRoot(userId, GenerateUniqueInviteCode()); - myInviteCode.MarkUserAsInvited(); - await _inviteCodeRepository.InsertAsync(myInviteCode); - } - else if (!myInviteCode.IsUserInvited) - { - myInviteCode.MarkUserAsInvited(); - await _inviteCodeRepository.UpdateAsync(myInviteCode); - } - - // 创建邀请记录 + + // 创建邀请记录(双方都会因为这条记录增加一次翻牌机会) var invitationRecord = new InvitationRecordAggregateRoot( inviteCodeEntity.UserId, userId, inviteCode); await _invitationRecordRepository.InsertAsync(invitationRecord); - _logger.LogInformation($"用户 {userId} 使用邀请码 {inviteCode} 成功"); + _logger.LogInformation($"用户 {userId} 使用邀请码 {inviteCode} 成功,邀请人 {inviteCodeEntity.UserId} 和被邀请人 {userId} 都增加一次翻牌机会"); return inviteCodeEntity.UserId; } /// - /// 检查用户是否已被邀请 + /// 检查用户是否已填写过邀请码 /// - public async Task IsUserInvitedAsync(Guid userId) + public async Task IsFilledInviteCodeAsync(Guid userId) { - var inviteCode = await _inviteCodeRepository._DbQueryable - .Where(x => x.UserId == userId) - .FirstAsync(); - - return inviteCode?.IsUserInvited ?? false; + // 检查当前用户是否已经填写过别人的邀请码(一辈子只能填写一次) + return await _invitationRecordRepository._DbQueryable + .Where(x => x.InvitedUserId == userId) + .AnyAsync(); } /// diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Caches/FileCacheItem.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Caches/FileCacheItem.cs index 47a91d4f..a8bfe3ab 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Caches/FileCacheItem.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain.Shared/Caches/FileCacheItem.cs @@ -1,4 +1,4 @@ -namespace Yi.Framework.Rbac.Domain.Shared.Caches; +namespace Yi.Framework.Rbac.Domain.Shared.Caches; public class FileCacheItem { diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs index 1e701178..a7d136b7 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs +++ b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs @@ -29,6 +29,7 @@ using Volo.Abp.Swashbuckle; using Yi.Abp.Application; using Yi.Abp.SqlsugarCore; using Yi.Framework.AiHub.Application; +using Yi.Framework.AiHub.Application.Services; using Yi.Framework.AiHub.Domain.Entities; using Yi.Framework.AspNetCore; using Yi.Framework.AspNetCore.Authentication.OAuth; @@ -354,7 +355,10 @@ namespace Yi.Abp.Web var app = context.GetApplicationBuilder(); app.UseRouting(); - //app.ApplicationServices.GetRequiredService().SqlSugarClient.CodeFirst.InitTables(); + // app.ApplicationServices.GetRequiredService().SqlSugarClient.CodeFirst.InitTables(); + // app.ApplicationServices.GetRequiredService().SqlSugarClient.CodeFirst.InitTables(); + // app.ApplicationServices.GetRequiredService().SqlSugarClient.CodeFirst.InitTables(); + // app.ApplicationServices.GetRequiredService().SqlSugarClient.CodeFirst.InitTables(); //跨域 app.UseCors(DefaultCorsPolicyName); diff --git a/Yi.Ai.Vue3/.claude/settings.local.json b/Yi.Ai.Vue3/.claude/settings.local.json new file mode 100644 index 00000000..4477e4c3 --- /dev/null +++ b/Yi.Ai.Vue3/.claude/settings.local.json @@ -0,0 +1,9 @@ +{ + "permissions": { + "allow": [ + "Bash(npx vue-tsc --noEmit)" + ], + "deny": [], + "ask": [] + } +} diff --git a/Yi.Ai.Vue3/index.html b/Yi.Ai.Vue3/index.html index 88c0e7d3..312c6934 100644 --- a/Yi.Ai.Vue3/index.html +++ b/Yi.Ai.Vue3/index.html @@ -112,7 +112,7 @@
-
意心Ai 2.2
+
意心Ai 2.3
海外地址,仅首次访问预计加载约10秒