From e6b991fe861e1e6548360432e4ba8c3a0b154c4a Mon Sep 17 00:00:00 2001 From: chenchun Date: Wed, 29 Oct 2025 21:55:17 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=B0=83=E6=95=B4=E7=BF=BB=E7=89=8C?= =?UTF-8?q?=E4=B8=8E=E9=82=80=E8=AF=B7=E7=A0=81=E9=80=BB=E8=BE=91=EF=BC=8C?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=AC=AC8=E6=AC=A1=E5=A5=96=E5=8A=B1?= =?UTF-8?q?=E5=8F=8A=E5=89=8D=E7=AB=AF=E9=AA=A8=E6=9E=B6=E5=B1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/CardFlipService.cs | 23 ++-- .../Entities/CardFlipTaskAggregateRoot.cs | 24 +++- .../Managers/CardFlipManager.cs | 101 +++++++++------ Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs | 4 +- .../components/CardFlipActivity.vue | 116 +++++++++++++++--- 5 files changed, 202 insertions(+), 66 deletions(-) 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 d0668225..45366c60 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 @@ -198,14 +198,25 @@ public class CardFlipService : ApplicationService, ICardFlipService }; // 设置中奖信息 + // 判断这张卡是第几次翻的 if (task != null && flippedNumbers.Contains(i)) { - if (i == 9 && task.HasNinthReward) + var flipOrderIndex = flippedOrder.IndexOf(i) + 1; // 第几次翻的(1-based) + + // 第8次翻的卡中奖 + if (flipOrderIndex == 8) + { + record.IsWin = true; + record.RewardAmount = task.EighthRewardAmount; + } + // 第9次翻的卡中奖 + else if (flipOrderIndex == 9) { record.IsWin = true; record.RewardAmount = task.NinthRewardAmount; } - else if (i == 10 && task.HasTenthReward) + // 第10次翻的卡中奖 + else if (flipOrderIndex == 10) { record.IsWin = true; record.RewardAmount = task.TenthRewardAmount; @@ -232,15 +243,11 @@ public class CardFlipService : ApplicationService, ICardFlipService { return $"还有{status.RemainingFreeFlips}次免费翻牌机会"; } - else if (status.RemainingBonusFlips > 0) - { - return $"还有{status.RemainingBonusFlips}次赠送翻牌机会"; - } else if (status.RemainingInviteFlips > 0) { - if (status.TotalFlips == 8) + if (status.TotalFlips >= 7) { - return "再邀请一个人,马上中奖!"; + return $"使用邀请码可解锁{status.RemainingInviteFlips}次翻牌,必中大奖!"; } return $"使用邀请码可解锁{status.RemainingInviteFlips}次翻牌"; 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 a13bb813..3bce9f1b 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 @@ -65,13 +65,23 @@ public class CardFlipTaskAggregateRoot : FullAuditedAggregateRoot /// public bool IsFirstFlipDone { get; set; } + /// + /// 是否已获得第8次奖励 + /// + public bool HasEighthReward { get; set; } + + /// + /// 第8次奖励金额(100-300w) + /// + public long? EighthRewardAmount { get; set; } + /// /// 是否已获得第9次奖励 /// public bool HasNinthReward { get; set; } /// - /// 第9次奖励金额(300-700w) + /// 第9次奖励金额(100-500w) /// public long? NinthRewardAmount { get; set; } @@ -81,7 +91,7 @@ public class CardFlipTaskAggregateRoot : FullAuditedAggregateRoot public bool HasTenthReward { get; set; } /// - /// 第10次奖励金额(800-1200w) + /// 第10次奖励金额(100-1000w) /// public long? TenthRewardAmount { get; set; } @@ -124,6 +134,16 @@ public class CardFlipTaskAggregateRoot : FullAuditedAggregateRoot } } + /// + /// 记录第8次奖励 + /// + /// 奖励金额 + public void SetEighthReward(long amount) + { + HasEighthReward = true; + EighthRewardAmount = amount; + } + /// /// 记录第9次奖励 /// 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 faa6ec16..cbd73343 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 @@ -14,18 +14,21 @@ public class CardFlipManager : DomainService private readonly ILogger _logger; // 翻牌规则配置 - public const int MAX_FREE_FLIPS = 5; // 免费翻牌次数 - public const int MAX_BONUS_FLIPS = 3; // 赠送翻牌次数 - public const int MAX_INVITE_FLIPS = 2; // 邀请解锁翻牌次数 + public const int MAX_FREE_FLIPS = 7; // 免费翻牌次数 + public const int MAX_BONUS_FLIPS = 0; // 赠送翻牌次数(已废弃) + public const int MAX_INVITE_FLIPS = 3; // 邀请解锁翻牌次数 public const int TOTAL_MAX_FLIPS = 10; // 总最大翻牌次数 + private const int EIGHTH_FLIP = 8; // 第8次翻牌 private const int NINTH_FLIP = 9; // 第9次翻牌 private const int TENTH_FLIP = 10; // 第10次翻牌 - private const long NINTH_MIN_REWARD = 3000000; // 第9次最小奖励 300w - private const long NINTH_MAX_REWARD = 7000000; // 第9次最大奖励 700w - private const long TENTH_MIN_REWARD = 8000000; // 第10次最小奖励 800w - private const long TENTH_MAX_REWARD = 12000000; // 第10次最大奖励 1200w + 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 + private const long NINTH_MAX_REWARD = 5000000; // 第9次最大奖励 500w + private const long TENTH_MIN_REWARD = 1000000; // 第10次最小奖励 100w + private const long TENTH_MAX_REWARD = 10000000; // 第10次最大奖励 1000w public CardFlipManager( ISqlSugarRepository cardFlipTaskRepository, @@ -104,23 +107,14 @@ public class CardFlipManager : DomainService throw new UserFriendlyException(GetFlipTypeErrorMessage(flipType)); } - // 计算翻牌结果 - var result = CalculateFlipResult(flipNumber); + // 计算翻牌结果(基于当前是第几次翻牌,而不是卡片序号) + var flipCount = task.TotalFlips + 1; // 当前这次翻牌是第几次 + var result = CalculateFlipResult(flipCount); - // 记录奖励 - if (result.IsWin) - { - if (flipNumber == NINTH_FLIP) - { - task.SetNinthReward(result.RewardAmount); - } - else if (flipNumber == TENTH_FLIP) - { - task.SetTenthReward(result.RewardAmount); - } - } + // 将卡片序号信息也返回 + result.FlipNumber = flipNumber; - // 更新翻牌次数 + // 更新翻牌次数(必须在记录奖励之前,因为需要先确定是第几次) task.IncrementFlip(flipType); // 记录翻牌顺序 @@ -130,6 +124,23 @@ public class CardFlipManager : DomainService } task.FlippedOrder.Add(flipNumber); + // 如果中奖,记录奖励金额(用于后续查询显示) + 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); + } + } + await _cardFlipTaskRepository.UpdateAsync(task); _logger.LogInformation($"用户 {userId} 完成第 {flipNumber} 次翻牌,中奖:{result.IsWin}"); @@ -183,37 +194,45 @@ public class CardFlipManager : DomainService /// /// 计算翻牌结果 /// - private FlipResult CalculateFlipResult(int flipNumber) + /// 第几次翻牌(1-10) + private FlipResult CalculateFlipResult(int flipCount) { var result = new FlipResult { - FlipNumber = flipNumber, + FlipNumber = 0, // 稍后会被设置为实际的卡片序号 IsWin = false, ShowDoubleRewardTip = false }; - // 前8次固定失败 - if (flipNumber <= 8) + // 前7次固定失败 + if (flipCount <= 7) { result.IsWin = false; result.RewardDesc = "很遗憾,未中奖"; } - // 第9次中奖 - else if (flipNumber == NINTH_FLIP) + // 第8次中奖 (邀请码解锁) + else if (flipCount == EIGHTH_FLIP) + { + var rewardAmount = GenerateRandomReward(EIGHTH_MIN_REWARD, EIGHTH_MAX_REWARD); + result.IsWin = true; + result.RewardAmount = rewardAmount; + result.RewardDesc = $"恭喜获得尊享包 {rewardAmount / 10000}w tokens!"; + } + // 第9次中奖 (邀请码解锁) + else if (flipCount == NINTH_FLIP) { var rewardAmount = GenerateRandomReward(NINTH_MIN_REWARD, NINTH_MAX_REWARD); result.IsWin = true; result.RewardAmount = rewardAmount; result.RewardDesc = $"恭喜获得尊享包 {rewardAmount / 10000}w tokens!"; - result.ShowDoubleRewardTip = true; // 显示翻倍包提示 } - // 第10次中奖(翻倍) - else if (flipNumber == TENTH_FLIP) + // 第10次中奖 (邀请码解锁) + else if (flipCount == TENTH_FLIP) { var rewardAmount = GenerateRandomReward(TENTH_MIN_REWARD, TENTH_MAX_REWARD); result.IsWin = true; result.RewardAmount = rewardAmount; - result.RewardDesc = $"恭喜获得尊享包 {rewardAmount / 10000}w tokens(翻倍奖励)!"; + result.RewardDesc = $"恭喜获得尊享包 {rewardAmount / 10000}w tokens!"; } return result; @@ -234,12 +253,22 @@ public class CardFlipManager : DomainService } /// - /// 生成随机奖励金额 + /// 生成随机奖励金额 (最小单位100w) /// private long GenerateRandomReward(long min, long max) { var random = new Random(); - return (long)(random.NextDouble() * (max - min) + min); + const long unit = 1000000; // 100w的单位 + + // 将min和max转换为100w的倍数 + long minUnits = min / unit; + long maxUnits = max / unit; + + // 在倍数范围内随机 + long randomUnits = random.Next((int)minUnits, (int)maxUnits + 1); + + // 返回100w的倍数 + return randomUnits * unit; } /// @@ -265,10 +294,6 @@ public class CardFlipManager : DomainService { return "免费"; } - else if (flipNumber <= MAX_FREE_FLIPS + MAX_BONUS_FLIPS) - { - return "赠送"; - } else { return "邀请解锁"; diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs index 89a44565..672e8164 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs +++ b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs @@ -352,7 +352,9 @@ 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.UseCors(DefaultCorsPolicyName); diff --git a/Yi.Ai.Vue3/src/components/userPersonalCenter/components/CardFlipActivity.vue b/Yi.Ai.Vue3/src/components/userPersonalCenter/components/CardFlipActivity.vue index f85c7563..d1ad1fc3 100644 --- a/Yi.Ai.Vue3/src/components/userPersonalCenter/components/CardFlipActivity.vue +++ b/Yi.Ai.Vue3/src/components/userPersonalCenter/components/CardFlipActivity.vue @@ -5,7 +5,8 @@ import { onMounted, ref } from 'vue'; import { flipCard, generateMyInviteCode, getWeeklyTaskStatus, useInviteCode } from '@/api/cardFlip'; const taskData = ref(null); -const loading = ref(false); +const loading = ref(false); // 操作加载状态(使用邀请码等) +const initialLoading = ref(true); // 初始加载状态 const flipping = ref(false); const inviteCodeDialog = ref(false); const inputInviteCode = ref(''); @@ -22,7 +23,15 @@ onMounted(() => { // 获取任务状态 async function fetchTaskStatus() { - loading.value = true; + // 首次加载时使用 initialLoading,避免白屏闪烁 + const isInitialLoad = taskData.value === null; + if (isInitialLoad) { + initialLoading.value = true; + } + else { + loading.value = true; + } + try { const res = await getWeeklyTaskStatus(); taskData.value = res.data; @@ -31,7 +40,12 @@ async function fetchTaskStatus() { ElMessage.error(error?.message || '获取任务状态失败'); } finally { - loading.value = false; + if (isInitialLoad) { + initialLoading.value = false; + } + else { + loading.value = false; + } } } @@ -42,11 +56,17 @@ async function handleFlipCard(record: CardFlipRecord) { if (canFlip) { // 检查是否需要使用邀请码 - if (record.flipNumber > 8 && (taskData.value?.remainingInviteFlips || 0) > 0) { - const usedInviteFlips = 2 - (taskData.value?.remainingInviteFlips || 2); - if (usedInviteFlips < (record.flipNumber - 8)) { + // 当前已翻次数 + const currentFlips = taskData.value?.totalFlips || 0; + + // 如果已经翻了7次或以上,需要检查邀请码 + if (currentFlips >= 7) { + const remainingInviteFlips = taskData.value?.remainingInviteFlips || 0; + + // 如果没有剩余邀请次数,提示需要使用邀请码 + if (remainingInviteFlips === 0) { ElMessageBox.confirm( - '🎁 需要先使用邀请码解锁此次翻牌机会哦~', + '🎁 需要先使用邀请码解锁更多翻牌机会哦~', '温馨提示', { confirmButtonText: '去使用', @@ -62,13 +82,17 @@ async function handleFlipCard(record: CardFlipRecord) { } } + // 标记为正在翻牌(显示加载状态,但不播放动画) flipping.value = true; - flippingCards.value.add(record.flipNumber); try { + // 先请求后端接口 const res = await flipCard({ flipNumber: record.flipNumber }); lastFlipResult.value = res.data; + // 请求成功后,开始播放翻牌动画 + flippingCards.value.add(record.flipNumber); + // 等待翻牌动画完成 await new Promise(resolve => setTimeout(resolve, 800)); @@ -105,6 +129,8 @@ async function handleFlipCard(record: CardFlipRecord) { } catch (error: any) { ElMessage.error(error?.message || '翻牌失败'); + // 如果请求失败,移除翻牌动画 + flippingCards.value.delete(record.flipNumber); } finally { flipping.value = false; @@ -236,8 +262,20 @@ function toggleInviteSection() { @@ -1139,4 +1173,52 @@ function toggleInviteSection() { opacity: 1; } } + +/* 骨架屏样式 */ +.loading-skeleton { + padding: 16px 0; + + .skeleton-stats { + display: flex; + gap: 12px; + margin-bottom: 16px; + } + + .skeleton-stat-item { + flex: 1; + height: 64px; + background: linear-gradient(90deg, rgba(255, 255, 255, 0.1) 25%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.1) 75%); + background-size: 200% 100%; + border-radius: 12px; + animation: skeleton-loading 1.5s ease-in-out infinite; + } + + .skeleton-cards { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: 10px; + + @media (max-width: 768px) { + grid-template-columns: repeat(5, 1fr); + gap: 8px; + } + } + + .skeleton-card { + aspect-ratio: 3/4; + background: linear-gradient(90deg, rgba(255, 255, 255, 0.1) 25%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.1) 75%); + background-size: 200% 100%; + border-radius: 10px; + animation: skeleton-loading 1.5s ease-in-out infinite; + } +} + +@keyframes skeleton-loading { + 0% { + background-position: 200% 0; + } + 100% { + background-position: -200% 0; + } +}