diff --git a/client/js/scenes/EndingScene.js b/client/js/scenes/EndingScene.js index 2443807..3f985de 100644 --- a/client/js/scenes/EndingScene.js +++ b/client/js/scenes/EndingScene.js @@ -18,7 +18,16 @@ export default class EndingScene extends BaseScene { this.rewritePrompt = ''; this.rewriteTags = ['主角逆袭', '甜蜜HE', '虐心BE', '反转剧情', '意外重逢']; this.selectedTag = -1; + // 改写历史 + this.rewriteHistory = []; + this.currentHistoryIndex = -1; + // 配额信息 + this.aiQuota = { daily: 3, used: 0, purchased: 0 }; + // 加载状态 + this.isRewriting = false; + this.rewriteProgress = 0; this.initParticles(); + this.loadQuota(); } init() { @@ -27,6 +36,17 @@ export default class EndingScene extends BaseScene { }, 1500); } + async loadQuota() { + try { + const quota = await this.main.userManager.getAIQuota(); + if (quota) { + this.aiQuota = quota; + } + } catch (e) { + console.error('加载配额失败:', e); + } + } + initParticles() { for (let i = 0; i < 50; i++) { this.particles.push({ @@ -228,13 +248,15 @@ export default class EndingScene extends BaseScene { const buttonHeight = 38; const buttonMargin = 8; const startY = this.screenHeight - 220; - const buttonWidth = (this.screenWidth - padding * 2 - buttonMargin) / 2; - // AI改写按钮(突出显示) - this.renderGradientButton(ctx, padding, startY, this.screenWidth - padding * 2, buttonHeight, '✨ AI改写结局', ['#a855f7', '#ec4899']); + // AI改写按钮(带配额提示) + const remaining = this.aiQuota.daily - this.aiQuota.used + this.aiQuota.purchased; + const aiBtnText = remaining > 0 ? '✨ AI改写结局' : '⚠️ 次数不足'; + this.renderGradientButton(ctx, padding, startY, this.screenWidth - padding * 2, buttonHeight, aiBtnText, ['#a855f7', '#ec4899']); // 分享按钮 const row2Y = startY + buttonHeight + buttonMargin; + const buttonWidth = (this.screenWidth - padding * 2 - buttonMargin) / 2; this.renderGradientButton(ctx, padding, row2Y, buttonWidth, buttonHeight, '分享结局', ['#ff6b6b', '#ffd700']); // 章节选择按钮 @@ -298,12 +320,12 @@ export default class EndingScene extends BaseScene { renderRewritePanel(ctx) { const padding = 20; const panelWidth = this.screenWidth - padding * 2; - const panelHeight = 380; + const panelHeight = 450; const panelX = padding; const panelY = (this.screenHeight - panelHeight) / 2; // 遮罩层 - ctx.fillStyle = 'rgba(0, 0, 0, 0.8)'; + ctx.fillStyle = 'rgba(0, 0, 0, 0.85)'; ctx.fillRect(0, 0, this.screenWidth, this.screenHeight); // 面板背景渐变 @@ -323,15 +345,23 @@ export default class EndingScene extends BaseScene { this.roundRect(ctx, panelX, panelY, panelWidth, panelHeight, 20); ctx.stroke(); - // 标题 + // 标题栏 ctx.fillStyle = '#ffffff'; ctx.font = 'bold 18px sans-serif'; ctx.textAlign = 'center'; ctx.fillText('✨ AI改写结局', this.screenWidth / 2, panelY + 35); + // 配额提示 + const remaining = this.aiQuota.daily - this.aiQuota.used + this.aiQuota.purchased; + ctx.fillStyle = remaining > 0 ? 'rgba(255,255,255,0.6)' : 'rgba(255,100,100,0.8)'; + ctx.font = '11px sans-serif'; + ctx.textAlign = 'right'; + ctx.fillText(`剩余次数:${remaining}`, panelX + panelWidth - 15, panelY + 35); + // 副标题 ctx.fillStyle = 'rgba(255,255,255,0.6)'; ctx.font = '12px sans-serif'; + ctx.textAlign = 'center'; ctx.fillText('输入你想要的剧情走向,AI将为你重新创作', this.screenWidth / 2, panelY + 58); // 分隔线 @@ -641,6 +671,13 @@ export default class EndingScene extends BaseScene { } handleAIRewrite() { + // 检查配额 + const remaining = this.aiQuota.daily - this.aiQuota.used + this.aiQuota.purchased; + if (remaining <= 0) { + this.showQuotaModal(); + return; + } + // 显示AI改写面板 this.showRewritePanel = true; this.rewritePrompt = ''; @@ -701,7 +738,27 @@ export default class EndingScene extends BaseScene { } async callAIRewrite(prompt) { - wx.showLoading({ title: 'AI创作中...' }); + // 检查配额 + const remaining = this.aiQuota.daily - this.aiQuota.used + this.aiQuota.purchased; + if (remaining <= 0) { + this.showQuotaModal(); + return; + } + + this.isRewriting = true; + this.rewriteProgress = 0; + + // 显示加载动画 + wx.showLoading({ + title: 'AI创作中...', + mask: true + }); + + // 模拟进度条效果 + const progressInterval = setInterval(() => { + this.rewriteProgress += Math.random() * 20; + if (this.rewriteProgress > 90) this.rewriteProgress = 90; + }, 500); try { const result = await this.main.storyManager.rewriteEnding( @@ -710,23 +767,73 @@ export default class EndingScene extends BaseScene { prompt ); + clearInterval(progressInterval); + this.rewriteProgress = 100; wx.hideLoading(); if (result && result.content) { - // 跳转到故事场景播放新内容 - this.main.sceneManager.switchScene('story', { - storyId: this.storyId, - aiContent: result + // 记录改写历史 + this.rewriteHistory.push({ + prompt: prompt, + content: result.content, + timestamp: Date.now() }); + this.currentHistoryIndex = this.rewriteHistory.length - 1; + + // 扣除配额 + this.aiQuota.used += 1; + + // 成功提示 + wx.showToast({ + title: '改写成功!', + icon: 'success', + duration: 1500 + }); + + // 延迟跳转到故事场景播放新内容 + setTimeout(() => { + this.main.sceneManager.switchScene('story', { + storyId: this.storyId, + aiContent: result + }); + }, 1500); } else { wx.showToast({ title: '改写失败,请重试', icon: 'none' }); } } catch (error) { + clearInterval(progressInterval); wx.hideLoading(); - wx.showToast({ title: '网络错误', icon: 'none' }); + console.error('改写失败:', error); + wx.showToast({ title: error.message || '网络错误', icon: 'none' }); + } finally { + this.isRewriting = false; + this.rewriteProgress = 0; } } + showQuotaModal() { + wx.showModal({ + title: 'AI次数不足', + content: `今日剩余免费次数已用完。\n\n观看广告可获得1次 AI改写机会`, + confirmText: '看广告', + cancelText: '取消', + success: (res) => { + if (res.confirm) { + this.watchAdForQuota(); + } + } + }); + } + + watchAdForQuota() { + // 模拟看广告获得配额 + wx.showToast({ + title: '获得1次 AI 次数', + icon: 'success' + }); + this.aiQuota.purchased += 1; + } + handleReplay() { this.main.storyManager.resetStory(); this.main.sceneManager.switchScene('story', { storyId: this.storyId });