feat: 创作中心改造 - 我的改写/续写Tab展示已发布作品
This commit is contained in:
@@ -6,8 +6,8 @@ import BaseScene from './BaseScene';
|
||||
export default class AICreateScene extends BaseScene {
|
||||
constructor(main, params) {
|
||||
super(main, params);
|
||||
this.currentTab = 0; // 0:改写 1:续写 2:创作
|
||||
this.tabs = ['AI改写', 'AI续写', 'AI创作'];
|
||||
this.currentTab = 0; // 0:我的改写 1:我的续写 2:AI创作
|
||||
this.tabs = ['我的改写', '我的续写', 'AI创作'];
|
||||
|
||||
// 滚动
|
||||
this.scrollY = 0;
|
||||
@@ -17,8 +17,8 @@ export default class AICreateScene extends BaseScene {
|
||||
this.hasMoved = false;
|
||||
|
||||
// 用户数据
|
||||
this.recentStories = [];
|
||||
this.aiHistory = [];
|
||||
this.publishedRewrites = []; // 已发布的改写作品
|
||||
this.publishedContinues = []; // 已发布的续写作品
|
||||
this.quota = { daily: 3, used: 0, purchased: 0 };
|
||||
|
||||
// 创作表单
|
||||
@@ -29,12 +29,7 @@ export default class AICreateScene extends BaseScene {
|
||||
conflict: ''
|
||||
};
|
||||
|
||||
// 选中的故事(用于改写/续写)
|
||||
this.selectedStory = null;
|
||||
|
||||
// 快捷标签
|
||||
this.rewriteTags = ['主角逆袭', '甜蜜HE', '虐心BE', '反转剧情', '意外重逢', '身份揭秘'];
|
||||
this.continueTags = ['增加悬念', '感情升温', '冲突加剧', '真相大白', '误会解除'];
|
||||
this.genreTags = ['都市言情', '古风宫廷', '悬疑推理', '校园青春', '修仙玄幻', '职场商战'];
|
||||
}
|
||||
|
||||
@@ -44,10 +39,17 @@ export default class AICreateScene extends BaseScene {
|
||||
|
||||
async loadData() {
|
||||
try {
|
||||
// 加载最近游玩的故事
|
||||
this.recentStories = await this.main.userManager.getRecentPlayed() || [];
|
||||
// 加载AI创作历史
|
||||
this.aiHistory = await this.main.userManager.getAIHistory() || [];
|
||||
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;
|
||||
@@ -59,8 +61,10 @@ export default class AICreateScene extends BaseScene {
|
||||
|
||||
calculateMaxScroll() {
|
||||
let contentHeight = 400;
|
||||
if (this.currentTab === 0 || this.currentTab === 1) {
|
||||
contentHeight = 300 + this.recentStories.length * 80;
|
||||
if (this.currentTab === 0) {
|
||||
contentHeight = 300 + this.publishedRewrites.length * 90;
|
||||
} else if (this.currentTab === 1) {
|
||||
contentHeight = 300 + this.publishedContinues.length * 90;
|
||||
} else {
|
||||
contentHeight = 600;
|
||||
}
|
||||
@@ -210,23 +214,10 @@ export default class AICreateScene extends BaseScene {
|
||||
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.fillText('展示你从草稿箱发布的改写作品', this.screenWidth / 2, y + 25);
|
||||
|
||||
// 快捷标签
|
||||
ctx.fillStyle = 'rgba(255,255,255,0.8)';
|
||||
ctx.font = '12px sans-serif';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillText('热门改写方向:', padding, y + 55);
|
||||
|
||||
const tagEndY = this.renderTags(ctx, this.rewriteTags, padding, y + 70, 'rewrite');
|
||||
|
||||
// 选择故事 - 位置根据标签高度动态调整
|
||||
ctx.fillStyle = 'rgba(255,255,255,0.8)';
|
||||
ctx.font = '13px sans-serif';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillText('选择要改写的故事:', padding, tagEndY + 25);
|
||||
|
||||
this.renderStoryList(ctx, tagEndY + 40, 'rewrite');
|
||||
// 作品列表
|
||||
this.renderPublishedList(ctx, y + 50, this.publishedRewrites, 'rewrite');
|
||||
}
|
||||
|
||||
renderContinueTab(ctx, startY) {
|
||||
@@ -236,21 +227,10 @@ export default class AICreateScene extends BaseScene {
|
||||
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.fillText('展示你从草稿箱发布的续写作品', this.screenWidth / 2, y + 25);
|
||||
|
||||
ctx.fillStyle = 'rgba(255,255,255,0.8)';
|
||||
ctx.font = '12px sans-serif';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillText('续写方向:', padding, y + 55);
|
||||
|
||||
const tagEndY = this.renderTags(ctx, this.continueTags, padding, y + 70, 'continue');
|
||||
|
||||
ctx.fillStyle = 'rgba(255,255,255,0.8)';
|
||||
ctx.font = '13px sans-serif';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.fillText('选择要续写的故事:', padding, tagEndY + 25);
|
||||
|
||||
this.renderStoryList(ctx, tagEndY + 40, 'continue');
|
||||
// 作品列表
|
||||
this.renderPublishedList(ctx, y + 50, this.publishedContinues, 'continue');
|
||||
}
|
||||
|
||||
renderCreateTab(ctx, startY) {
|
||||
@@ -388,6 +368,84 @@ export default class AICreateScene extends BaseScene {
|
||||
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;
|
||||
@@ -550,7 +608,6 @@ export default class AICreateScene extends BaseScene {
|
||||
if (this.currentTab !== tab.index) {
|
||||
this.currentTab = tab.index;
|
||||
this.scrollY = 0;
|
||||
this.selectedStory = null;
|
||||
this.calculateMaxScroll();
|
||||
}
|
||||
return;
|
||||
@@ -561,14 +618,34 @@ export default class AICreateScene extends BaseScene {
|
||||
// 调整y坐标(考虑滚动)
|
||||
const scrolledY = y + this.scrollY;
|
||||
|
||||
// 标签点击
|
||||
if (this.tagRects) {
|
||||
const tagType = this.currentTab === 0 ? 'rewrite' : this.currentTab === 1 ? 'continue' : 'genre';
|
||||
const tags = this.tagRects[tagType];
|
||||
// 前往草稿箱按钮
|
||||
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(tagType, tag);
|
||||
this.handleTagSelect('genre', tag);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -586,26 +663,6 @@ export default class AICreateScene extends BaseScene {
|
||||
}
|
||||
}
|
||||
|
||||
// 故事列表点击
|
||||
if (this.currentTab < 2 && this.storyRects) {
|
||||
const type = this.currentTab === 0 ? 'rewrite' : 'continue';
|
||||
const stories = this.storyRects[type];
|
||||
if (stories) {
|
||||
for (const rect of stories) {
|
||||
if (this.isInRect(x, scrolledY, rect)) {
|
||||
this.selectedStory = rect.story;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 操作按钮
|
||||
if (this.actionBtnRect && this.isInRect(x, scrolledY, this.actionBtnRect)) {
|
||||
this.handleAction(this.actionBtnRect.type);
|
||||
return;
|
||||
}
|
||||
|
||||
// 创作按钮
|
||||
if (this.currentTab === 2 && this.createBtnRect && this.isInRect(x, scrolledY, this.createBtnRect)) {
|
||||
this.handleCreate();
|
||||
@@ -613,6 +670,15 @@ export default class AICreateScene extends BaseScene {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -620,10 +686,6 @@ export default class AICreateScene extends BaseScene {
|
||||
handleTagSelect(type, tag) {
|
||||
if (type === 'genre') {
|
||||
this.createForm.genre = tag.value;
|
||||
} else if (type === 'rewrite') {
|
||||
this.selectedRewriteTag = tag.index;
|
||||
} else if (type === 'continue') {
|
||||
this.selectedContinueTag = tag.index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user