Files
ai_game/client/js/scenes/AICreateScene.js

866 lines
26 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* AI创作中心场景
*/
import BaseScene from './BaseScene';
export default class AICreateScene extends BaseScene {
constructor(main, params) {
super(main, params);
this.currentTab = 0; // 0:我的改写 1:我的续写 2:AI创作
this.tabs = ['我的改写', '我的续写', 'AI创作'];
// 滚动
this.scrollY = 0;
this.maxScrollY = 0;
this.isDragging = false;
this.lastTouchY = 0;
this.hasMoved = false;
// 用户数据
this.publishedRewrites = []; // 已发布的改写作品
this.publishedContinues = []; // 已发布的续写作品
this.quota = { daily: 3, used: 0, purchased: 0 };
// 创作表单
this.createForm = {
genre: '',
keywords: '',
protagonist: '',
conflict: ''
};
// 快捷标签
this.genreTags = ['都市言情', '古风宫廷', '悬疑推理', '校园青春', '修仙玄幻', '职场商战'];
}
async init() {
await this.loadData();
}
async loadData() {
try {
const userId = this.main.userManager.userId;
if (!userId) return;
// 加载已发布的改写作品
const rewriteRes = await this.main.userManager.getPublishedDrafts('rewrite');
this.publishedRewrites = rewriteRes || [];
// 加载已发布的续写作品
const continueRes = await this.main.userManager.getPublishedDrafts('continue');
this.publishedContinues = continueRes || [];
// 加载配额
const quotaData = await this.main.userManager.getAIQuota();
if (quotaData) this.quota = quotaData;
} catch (e) {
console.error('加载数据失败:', e);
}
this.calculateMaxScroll();
}
calculateMaxScroll() {
let contentHeight = 400;
if (this.currentTab === 0) {
contentHeight = 300 + this.publishedRewrites.length * 90;
} else if (this.currentTab === 1) {
contentHeight = 300 + this.publishedContinues.length * 90;
} else {
contentHeight = 600;
}
this.maxScrollY = Math.max(0, contentHeight - this.screenHeight + 200);
}
update() {}
render(ctx) {
this.renderBackground(ctx);
this.renderHeader(ctx);
this.renderQuotaBar(ctx);
this.renderTabs(ctx);
this.renderContent(ctx);
}
renderBackground(ctx) {
const gradient = ctx.createLinearGradient(0, 0, 0, this.screenHeight);
gradient.addColorStop(0, '#0f0c29');
gradient.addColorStop(0.5, '#302b63');
gradient.addColorStop(1, '#24243e');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, this.screenWidth, this.screenHeight);
// 装饰光效
const glow = ctx.createRadialGradient(this.screenWidth / 2, 150, 0, this.screenWidth / 2, 150, 200);
glow.addColorStop(0, 'rgba(168, 85, 247, 0.15)');
glow.addColorStop(1, 'transparent');
ctx.fillStyle = glow;
ctx.fillRect(0, 0, this.screenWidth, 300);
}
renderHeader(ctx) {
// 顶部遮罩
const headerGradient = ctx.createLinearGradient(0, 0, 0, 80);
headerGradient.addColorStop(0, 'rgba(15,12,41,1)');
headerGradient.addColorStop(1, 'rgba(15,12,41,0)');
ctx.fillStyle = headerGradient;
ctx.fillRect(0, 0, this.screenWidth, 80);
// 返回按钮
ctx.fillStyle = '#ffffff';
ctx.font = '16px sans-serif';
ctx.textAlign = 'left';
ctx.fillText(' 返回', 15, 40);
// 标题
ctx.textAlign = 'center';
ctx.font = 'bold 18px sans-serif';
const titleGradient = ctx.createLinearGradient(this.screenWidth / 2 - 50, 0, this.screenWidth / 2 + 50, 0);
titleGradient.addColorStop(0, '#a855f7');
titleGradient.addColorStop(1, '#ec4899');
ctx.fillStyle = titleGradient;
ctx.fillText('✨ AI创作中心', this.screenWidth / 2, 40);
}
renderQuotaBar(ctx) {
const barY = 60;
const remaining = this.quota.daily - this.quota.used + this.quota.purchased;
// 配额背景
ctx.fillStyle = 'rgba(255,255,255,0.08)';
this.roundRect(ctx, 15, barY, this.screenWidth - 30, 36, 18);
ctx.fill();
// 配额文字
ctx.fillStyle = 'rgba(255,255,255,0.7)';
ctx.font = '12px sans-serif';
ctx.textAlign = 'left';
ctx.fillText(`今日剩余: ${remaining}`, 30, barY + 23);
// 充值按钮
const btnWidth = 70;
const btnX = this.screenWidth - 30 - btnWidth;
const btnGradient = ctx.createLinearGradient(btnX, barY + 5, btnX + btnWidth, barY + 5);
btnGradient.addColorStop(0, '#a855f7');
btnGradient.addColorStop(1, '#ec4899');
ctx.fillStyle = btnGradient;
this.roundRect(ctx, btnX, barY + 5, btnWidth, 26, 13);
ctx.fill();
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 11px sans-serif';
ctx.textAlign = 'center';
ctx.fillText('获取更多', btnX + btnWidth / 2, barY + 22);
this.quotaBtnRect = { x: btnX, y: barY + 5, width: btnWidth, height: 26 };
}
renderTabs(ctx) {
const tabY = 110;
const tabWidth = (this.screenWidth - 40) / 3;
const padding = 15;
this.tabRects = [];
this.tabs.forEach((tab, index) => {
const x = padding + index * (tabWidth + 5);
const isActive = index === this.currentTab;
if (isActive) {
const gradient = ctx.createLinearGradient(x, tabY, x + tabWidth, tabY);
gradient.addColorStop(0, '#a855f7');
gradient.addColorStop(1, '#ec4899');
ctx.fillStyle = gradient;
} else {
ctx.fillStyle = 'rgba(255,255,255,0.1)';
}
this.roundRect(ctx, x, tabY, tabWidth, 36, 18);
ctx.fill();
ctx.fillStyle = isActive ? '#ffffff' : 'rgba(255,255,255,0.6)';
ctx.font = isActive ? 'bold 13px sans-serif' : '13px sans-serif';
ctx.textAlign = 'center';
ctx.fillText(tab, x + tabWidth / 2, tabY + 23);
this.tabRects.push({ x, y: tabY, width: tabWidth, height: 36, index });
});
}
renderContent(ctx) {
const contentY = 160;
ctx.save();
ctx.beginPath();
ctx.rect(0, contentY, this.screenWidth, this.screenHeight - contentY);
ctx.clip();
switch (this.currentTab) {
case 0:
this.renderRewriteTab(ctx, contentY);
break;
case 1:
this.renderContinueTab(ctx, contentY);
break;
case 2:
this.renderCreateTab(ctx, contentY);
break;
}
ctx.restore();
}
renderRewriteTab(ctx, startY) {
const y = startY - this.scrollY;
const padding = 15;
// 说明文字
ctx.fillStyle = 'rgba(255,255,255,0.6)';
ctx.font = '13px sans-serif';
ctx.textAlign = 'center';
ctx.fillText('展示你从草稿箱发布的改写作品', this.screenWidth / 2, y + 25);
// 作品列表
this.renderPublishedList(ctx, y + 50, this.publishedRewrites, 'rewrite');
}
renderContinueTab(ctx, startY) {
const y = startY - this.scrollY;
const padding = 15;
ctx.fillStyle = 'rgba(255,255,255,0.6)';
ctx.font = '13px sans-serif';
ctx.textAlign = 'center';
ctx.fillText('展示你从草稿箱发布的续写作品', this.screenWidth / 2, y + 25);
// 作品列表
this.renderPublishedList(ctx, y + 50, this.publishedContinues, 'continue');
}
renderCreateTab(ctx, startY) {
const y = startY - this.scrollY;
const padding = 15;
const inputWidth = this.screenWidth - padding * 2;
ctx.fillStyle = 'rgba(255,255,255,0.6)';
ctx.font = '13px sans-serif';
ctx.textAlign = 'center';
ctx.fillText('输入关键词AI为你创作全新故事', this.screenWidth / 2, y + 25);
// 题材选择
ctx.fillStyle = 'rgba(255,255,255,0.8)';
ctx.font = '13px sans-serif';
ctx.textAlign = 'left';
ctx.fillText('选择题材:', padding, y + 55);
const tagEndY = this.renderTags(ctx, this.genreTags, padding, y + 70, 'genre');
// 关键词输入
let currentY = tagEndY + 25;
ctx.fillText('故事关键词:', padding, currentY);
this.renderInputBox(ctx, padding, currentY + 15, inputWidth, 45, this.createForm.keywords || '例如:霸总、契约婚姻、追妻火葬场', 'keywords');
// 主角设定
currentY += 80;
ctx.fillText('主角设定:', padding, currentY);
this.renderInputBox(ctx, padding, currentY + 15, inputWidth, 45, this.createForm.protagonist || '例如:独立女性设计师', 'protagonist');
// 核心冲突
currentY += 80;
ctx.fillText('核心冲突:', padding, currentY);
this.renderInputBox(ctx, padding, currentY + 15, inputWidth, 45, this.createForm.conflict || '例如:假结婚变真爱', 'conflict');
// 开始创作按钮
const btnY = currentY + 85;
const btnGradient = ctx.createLinearGradient(padding, btnY, this.screenWidth - padding, btnY);
btnGradient.addColorStop(0, '#a855f7');
btnGradient.addColorStop(1, '#ec4899');
ctx.fillStyle = btnGradient;
this.roundRect(ctx, padding, btnY, inputWidth, 50, 25);
ctx.fill();
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 16px sans-serif';
ctx.textAlign = 'center';
ctx.fillText('✨ 开始AI创作', this.screenWidth / 2, btnY + 32);
this.createBtnRect = { x: padding, y: btnY + this.scrollY, width: inputWidth, height: 50 };
}
renderTags(ctx, tags, startX, startY, type) {
const tagHeight = 30;
const tagGap = 8;
let currentX = startX;
let currentY = startY;
let maxY = startY + tagHeight; // 记录最大Y坐标
if (!this.tagRects) this.tagRects = {};
this.tagRects[type] = [];
tags.forEach((tag, index) => {
ctx.font = '12px sans-serif';
const tagWidth = ctx.measureText(tag).width + 20;
if (currentX + tagWidth > this.screenWidth - 15) {
currentX = startX;
currentY += tagHeight + tagGap;
maxY = currentY + tagHeight;
}
const isSelected = (type === 'genre' && this.createForm.genre === tag) ||
(type === 'rewrite' && this.selectedRewriteTag === index) ||
(type === 'continue' && this.selectedContinueTag === index);
if (isSelected) {
const gradient = ctx.createLinearGradient(currentX, currentY, currentX + tagWidth, currentY);
gradient.addColorStop(0, '#a855f7');
gradient.addColorStop(1, '#ec4899');
ctx.fillStyle = gradient;
} else {
ctx.fillStyle = 'rgba(255,255,255,0.1)';
}
this.roundRect(ctx, currentX, currentY, tagWidth, tagHeight, 15);
ctx.fill();
if (!isSelected) {
ctx.strokeStyle = 'rgba(255,255,255,0.2)';
ctx.lineWidth = 1;
this.roundRect(ctx, currentX, currentY, tagWidth, tagHeight, 15);
ctx.stroke();
}
ctx.fillStyle = '#ffffff';
ctx.textAlign = 'center';
ctx.fillText(tag, currentX + tagWidth / 2, currentY + 20);
this.tagRects[type].push({
x: currentX,
y: currentY + this.scrollY,
width: tagWidth,
height: tagHeight,
index,
value: tag
});
currentX += tagWidth + tagGap;
});
return maxY; // 返回标签区域结束的Y坐标
}
renderInputBox(ctx, x, y, width, height, placeholder, field) {
ctx.fillStyle = 'rgba(255,255,255,0.08)';
this.roundRect(ctx, x, y, width, height, 12);
ctx.fill();
ctx.strokeStyle = 'rgba(255,255,255,0.2)';
ctx.lineWidth = 1;
this.roundRect(ctx, x, y, width, height, 12);
ctx.stroke();
ctx.font = '13px sans-serif';
ctx.textAlign = 'left';
if (this.createForm[field]) {
ctx.fillStyle = '#ffffff';
ctx.fillText(this.createForm[field], x + 15, y + height / 2 + 5);
} else {
ctx.fillStyle = 'rgba(255,255,255,0.4)';
ctx.fillText(placeholder, x + 15, y + height / 2 + 5);
}
if (!this.inputRects) this.inputRects = {};
this.inputRects[field] = { x, y: y + this.scrollY, width, height, field };
}
renderPublishedList(ctx, startY, items, type) {
const padding = 15;
const cardHeight = 80;
const cardGap = 12;
if (!this.publishedRects) this.publishedRects = {};
this.publishedRects[type] = [];
if (!items || items.length === 0) {
ctx.fillStyle = 'rgba(255,255,255,0.4)';
ctx.font = '13px sans-serif';
ctx.textAlign = 'center';
const tipText = type === 'rewrite'
? '暂无改写作品,去草稿箱发布吧'
: '暂无续写作品,去草稿箱发布吧';
ctx.fillText(tipText, this.screenWidth / 2, startY + 40);
// 跳转草稿箱按钮
const btnY = startY + 70;
const btnWidth = 120;
const btnX = (this.screenWidth - btnWidth) / 2;
ctx.fillStyle = 'rgba(168, 85, 247, 0.3)';
this.roundRect(ctx, btnX, btnY, btnWidth, 36, 18);
ctx.fill();
ctx.fillStyle = '#a855f7';
ctx.font = '13px sans-serif';
ctx.fillText('前往草稿箱', this.screenWidth / 2, btnY + 24);
this.gotoDraftsBtnRect = { x: btnX, y: btnY + this.scrollY, width: btnWidth, height: 36 };
return;
}
items.forEach((item, index) => {
const y = startY + index * (cardHeight + cardGap);
// 卡片背景
ctx.fillStyle = 'rgba(255,255,255,0.06)';
this.roundRect(ctx, padding, y, this.screenWidth - padding * 2, cardHeight, 12);
ctx.fill();
// 标题
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 14px sans-serif';
ctx.textAlign = 'left';
const title = item.title?.length > 15 ? item.title.substring(0, 15) + '...' : (item.title || '未命名作品');
ctx.fillText(title, padding + 15, y + 25);
// 原故事
ctx.fillStyle = 'rgba(255,255,255,0.5)';
ctx.font = '11px sans-serif';
ctx.fillText(`原故事:${item.storyTitle || '未知'}`, padding + 15, y + 45);
// 创作时间
ctx.fillText(item.createdAt || '', padding + 15, y + 65);
// 阅读按钮
const btnX = this.screenWidth - padding - 70;
const btnGradient = ctx.createLinearGradient(btnX, y + 25, btnX + 60, y + 25);
btnGradient.addColorStop(0, '#a855f7');
btnGradient.addColorStop(1, '#ec4899');
ctx.fillStyle = btnGradient;
this.roundRect(ctx, btnX, y + 25, 60, 30, 15);
ctx.fill();
ctx.fillStyle = '#ffffff';
ctx.font = '12px sans-serif';
ctx.textAlign = 'center';
ctx.fillText('阅读', btnX + 30, y + 45);
this.publishedRects[type].push({
x: padding,
y: y + this.scrollY,
width: this.screenWidth - padding * 2,
height: cardHeight,
item,
btnRect: { x: btnX, y: y + 25 + this.scrollY, width: 60, height: 30 }
});
});
}
renderStoryList(ctx, startY, type) {
const padding = 15;
const cardHeight = 70;
const cardGap = 10;
if (!this.storyRects) this.storyRects = {};
this.storyRects[type] = [];
if (this.recentStories.length === 0) {
ctx.fillStyle = 'rgba(255,255,255,0.4)';
ctx.font = '13px sans-serif';
ctx.textAlign = 'center';
ctx.fillText('暂无游玩记录,去首页体验故事吧', this.screenWidth / 2, startY + 40);
return;
}
this.recentStories.forEach((story, index) => {
const y = startY + index * (cardHeight + cardGap);
const isSelected = this.selectedStory?.id === story.id;
// 卡片背景
if (isSelected) {
ctx.fillStyle = 'rgba(168, 85, 247, 0.2)';
} else {
ctx.fillStyle = 'rgba(255,255,255,0.06)';
}
this.roundRect(ctx, padding, y, this.screenWidth - padding * 2, cardHeight, 12);
ctx.fill();
if (isSelected) {
ctx.strokeStyle = '#a855f7';
ctx.lineWidth = 2;
this.roundRect(ctx, padding, y, this.screenWidth - padding * 2, cardHeight, 12);
ctx.stroke();
}
// 封面占位
const coverSize = 50;
ctx.fillStyle = 'rgba(255,255,255,0.1)';
this.roundRect(ctx, padding + 10, y + 10, coverSize, coverSize, 8);
ctx.fill();
// 故事标题
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 14px sans-serif';
ctx.textAlign = 'left';
const title = story.title?.length > 12 ? story.title.substring(0, 12) + '...' : story.title;
ctx.fillText(title || '未知故事', padding + 70, y + 28);
// 分类和进度
ctx.fillStyle = 'rgba(255,255,255,0.5)';
ctx.font = '11px sans-serif';
ctx.fillText(`${story.category || '未分类'} · ${story.progress || '进行中'}`, padding + 70, y + 50);
// 选择按钮
const btnX = this.screenWidth - padding - 60;
ctx.fillStyle = isSelected ? '#a855f7' : 'rgba(255,255,255,0.2)';
this.roundRect(ctx, btnX, y + 20, 50, 30, 15);
ctx.fill();
ctx.fillStyle = '#ffffff';
ctx.font = '11px sans-serif';
ctx.textAlign = 'center';
ctx.fillText(isSelected ? '已选' : '选择', btnX + 25, y + 40);
this.storyRects[type].push({
x: padding,
y: y + this.scrollY,
width: this.screenWidth - padding * 2,
height: cardHeight,
story
});
});
// 开始按钮
if (this.selectedStory) {
const btnY = startY + this.recentStories.length * (cardHeight + cardGap) + 20;
const btnGradient = ctx.createLinearGradient(padding, btnY, this.screenWidth - padding, btnY);
btnGradient.addColorStop(0, '#a855f7');
btnGradient.addColorStop(1, '#ec4899');
ctx.fillStyle = btnGradient;
this.roundRect(ctx, padding, btnY, this.screenWidth - padding * 2, 48, 24);
ctx.fill();
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 15px sans-serif';
ctx.textAlign = 'center';
const btnText = type === 'rewrite' ? '✨ 开始AI改写' : '✨ 开始AI续写';
ctx.fillText(btnText, this.screenWidth / 2, btnY + 30);
this.actionBtnRect = {
x: padding,
y: btnY + this.scrollY,
width: this.screenWidth - padding * 2,
height: 48,
type
};
}
}
roundRect(ctx, x, y, width, height, radius) {
ctx.beginPath();
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
ctx.closePath();
}
onTouchStart(e) {
const touch = e.touches[0];
this.lastTouchY = touch.clientY;
this.touchStartY = touch.clientY;
this.hasMoved = false;
if (touch.clientY > 160) {
this.isDragging = true;
}
}
onTouchMove(e) {
if (!this.isDragging) return;
const touch = e.touches[0];
const deltaY = this.lastTouchY - touch.clientY;
if (Math.abs(deltaY) > 3) {
this.hasMoved = true;
}
this.scrollY += deltaY;
this.scrollY = Math.max(0, Math.min(this.scrollY, this.maxScrollY));
this.lastTouchY = touch.clientY;
}
onTouchEnd(e) {
this.isDragging = false;
if (this.hasMoved) return;
const touch = e.changedTouches[0];
const x = touch.clientX;
const y = touch.clientY;
// 返回按钮
if (y < 60 && x < 80) {
this.main.sceneManager.switchScene('home');
return;
}
// 配额按钮
if (this.quotaBtnRect && this.isInRect(x, y, this.quotaBtnRect)) {
this.showQuotaModal();
return;
}
// Tab切换
if (this.tabRects) {
for (const tab of this.tabRects) {
if (this.isInRect(x, y, tab)) {
if (this.currentTab !== tab.index) {
this.currentTab = tab.index;
this.scrollY = 0;
this.calculateMaxScroll();
}
return;
}
}
}
// 调整y坐标考虑滚动
const scrolledY = y + this.scrollY;
// 前往草稿箱按钮
if (this.gotoDraftsBtnRect && this.isInRect(x, scrolledY, this.gotoDraftsBtnRect)) {
this.main.sceneManager.switchScene('drafts');
return;
}
// 已发布作品点击(改写/续写Tab
if (this.currentTab < 2 && this.publishedRects) {
const type = this.currentTab === 0 ? 'rewrite' : 'continue';
const items = this.publishedRects[type];
if (items) {
for (const rect of items) {
// 阅读按钮点击
if (this.isInRect(x, scrolledY, rect.btnRect)) {
this.handleReadPublished(rect.item);
return;
}
}
}
}
// 标签点击只有创作Tab有标签
if (this.currentTab === 2 && this.tagRects) {
const tags = this.tagRects['genre'];
if (tags) {
for (const tag of tags) {
if (this.isInRect(x, scrolledY, tag)) {
this.handleTagSelect('genre', tag);
return;
}
}
}
}
// 输入框点击创作Tab
if (this.currentTab === 2 && this.inputRects) {
for (const key in this.inputRects) {
const rect = this.inputRects[key];
if (this.isInRect(x, scrolledY, rect)) {
this.showInputModal(rect.field);
return;
}
}
}
// 创作按钮
if (this.currentTab === 2 && this.createBtnRect && this.isInRect(x, scrolledY, this.createBtnRect)) {
this.handleCreate();
return;
}
}
handleReadPublished(item) {
// 跳转到故事场景播放AI改写/续写的内容
this.main.sceneManager.switchScene('story', {
storyId: item.storyId,
draftId: item.id,
fromDrafts: true
});
}
isInRect(x, y, rect) {
return x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height;
}
handleTagSelect(type, tag) {
if (type === 'genre') {
this.createForm.genre = tag.value;
}
}
showInputModal(field) {
const titles = {
keywords: '输入故事关键词',
protagonist: '输入主角设定',
conflict: '输入核心冲突'
};
wx.showModal({
title: titles[field],
editable: true,
placeholderText: '请输入...',
content: this.createForm[field] || '',
success: (res) => {
if (res.confirm && res.content) {
this.createForm[field] = res.content;
}
}
});
}
showQuotaModal() {
wx.showModal({
title: 'AI创作次数',
content: `今日剩余${this.quota.daily - this.quota.used}\n购买次数${this.quota.purchased}\n\n观看广告可获得1次`,
confirmText: '看广告',
success: (res) => {
if (res.confirm) {
this.watchAdForQuota();
}
}
});
}
watchAdForQuota() {
wx.showToast({ title: '获得1次AI次数', icon: 'success' });
this.quota.purchased += 1;
}
handleAction(type) {
if (!this.selectedStory) {
wx.showToast({ title: '请先选择故事', icon: 'none' });
return;
}
const remaining = this.quota.daily - this.quota.used + this.quota.purchased;
if (remaining <= 0) {
this.showQuotaModal();
return;
}
if (type === 'rewrite') {
this.startRewrite();
} else {
this.startContinue();
}
}
startRewrite() {
const tag = this.selectedRewriteTag !== undefined ? this.rewriteTags[this.selectedRewriteTag] : '';
wx.showModal({
title: 'AI改写',
content: '确定要改写这个故事的结局吗?',
editable: true,
placeholderText: tag || '输入改写方向(可选)',
success: async (res) => {
if (res.confirm) {
wx.showLoading({ title: 'AI创作中...' });
try {
const result = await this.main.storyManager.rewriteEnding(
this.selectedStory.id,
{ name: '当前结局', content: '' },
res.content || tag || '改写结局'
);
wx.hideLoading();
if (result) {
this.quota.used += 1;
this.main.sceneManager.switchScene('story', {
storyId: this.selectedStory.id,
aiContent: result
});
}
} catch (e) {
wx.hideLoading();
wx.showToast({ title: '创作失败', icon: 'none' });
}
}
}
});
}
startContinue() {
const tag = this.selectedContinueTag !== undefined ? this.continueTags[this.selectedContinueTag] : '';
wx.showModal({
title: 'AI续写',
content: '确定要让AI续写这个故事吗',
editable: true,
placeholderText: tag || '输入续写方向(可选)',
success: async (res) => {
if (res.confirm) {
wx.showLoading({ title: 'AI创作中...' });
try {
// TODO: 实现续写API
const result = await this.main.storyManager.continueStory(
this.selectedStory.id,
res.content || tag || '续写剧情'
);
wx.hideLoading();
if (result) {
this.quota.used += 1;
this.main.sceneManager.switchScene('story', {
storyId: this.selectedStory.id,
aiContent: result
});
}
} catch (e) {
wx.hideLoading();
wx.showToast({ title: '创作失败', icon: 'none' });
}
}
}
});
}
handleCreate() {
if (!this.createForm.genre) {
wx.showToast({ title: '请选择题材', icon: 'none' });
return;
}
if (!this.createForm.keywords) {
wx.showToast({ title: '请输入关键词', icon: 'none' });
return;
}
const remaining = this.quota.daily - this.quota.used + this.quota.purchased;
if (remaining < 5) {
wx.showModal({
title: '次数不足',
content: 'AI创作需要5次配额当前剩余' + remaining + '次',
confirmText: '获取更多',
success: (res) => {
if (res.confirm) this.showQuotaModal();
}
});
return;
}
wx.showModal({
title: '确认创作',
content: `题材:${this.createForm.genre}\n关键词:${this.createForm.keywords}\n\n将消耗5次AI次数`,
success: async (res) => {
if (res.confirm) {
wx.showLoading({ title: 'AI创作中...', mask: true });
try {
// TODO: 实现完整创作API
const result = await this.main.storyManager.createStory(this.createForm);
wx.hideLoading();
if (result) {
this.quota.used += 5;
wx.showToast({ title: '创作成功!', icon: 'success' });
// 跳转到新故事
setTimeout(() => {
this.main.sceneManager.switchScene('story', { storyId: result.storyId });
}, 1500);
}
} catch (e) {
wx.hideLoading();
wx.showToast({ title: '创作失败', icon: 'none' });
}
}
}
});
}
}