feat: ScriptDetailView 增强展示用户心愿和大纲元数据

This commit is contained in:
2026-07-26 11:54:12 +08:00
parent 0f0ae08b7e
commit b5af8b4ce8
@@ -14,6 +14,10 @@
<text class="eyebrow">PARALLEL LIFE</text>
<text class="script-title">{{ script?.title || '未命名剧本' }}</text>
<text class="script-summary">{{ script?.summary || '命运正在整理章节。' }}</text>
<view v-if="userWish" class="wish-block">
<text class="wish-label">💭 用户心愿</text>
<text class="wish-text">{{ userWish }}</text>
</view>
<view class="stats">
<view class="stat">
<text class="stat-value">{{ script?.style || '爽文' }}</text>
@@ -39,8 +43,17 @@
<Markdown :content="fullContent" />
</view>
<view v-else class="outline-list">
<view v-for="(item, index) in outline" :key="index" class="outline-card kos-card">
<view v-else-if="activeTab === 'outline'" class="outline-list">
<!-- 优先展示从后端保存的真实大纲来自 conversation.message.metadata -->
<view v-if="outlineFromMeta && outlineFromMeta.length" v-for="(item, index) in outlineFromMeta" :key="'meta-' + index" class="outline-card kos-card">
<view class="outline-node">{{ index + 1 }}</view>
<view class="outline-body">
<text class="outline-title">{{ item.title }}</text>
<text class="outline-text">{{ item.text }}</text>
</view>
</view>
<!-- fallback 到本地解析 -->
<view v-else v-for="(item, index) in outline" :key="'local-' + index" class="outline-card kos-card">
<view class="outline-node">{{ index + 1 }}</view>
<view class="outline-body">
<text class="outline-title">{{ item.title }}</text>
@@ -83,6 +96,34 @@ const lengthText = computed(() => {
return map[script.value?.length] || script.value?.length || '中篇'
})
/**
* 用户心愿原文(从 EpicScript.theme 字段读取)
*/
const userWish = computed(() => script.value?.theme || '')
/**
* 大纲(从 plotJson.stages.outline 读取后端真实保存的 outline JSON
* 后端 ShortNovelServiceImpl 在 novel_done 时会把 outline_created 事件累积到 metadata.stages.outline
*/
const outlineFromMeta = computed(() => {
const stages = script.value?.plotJson?.stages
if (!stages || !stages.outline) return []
const outline = stages.outline
const items = []
if (outline.title) items.push({ title: '标题', text: outline.title })
if (outline.logline) items.push({ title: '简介', text: outline.logline })
if (Array.isArray(outline.beats)) {
outline.beats.forEach((beat, i) => {
items.push({
title: beat.title || `章节 ${i + 1}`,
text: beat.text || beat.description || JSON.stringify(beat)
})
})
}
if (outline.ending) items.push({ title: '结局', text: outline.ending })
return items
})
const detailTtsActionText = computed(() => {
if (!script.value?.id) return '播放'
if (ttsPlayer.loading.value) return '生成中'
@@ -271,6 +312,30 @@ onUnmounted(() => {
line-height: 1.62;
}
.wish-block {
margin-top: 24rpx;
padding: 20rpx 22rpx;
border-radius: 22rpx;
background: linear-gradient(135deg, rgba(168, 85, 247, 0.16), rgba(232, 121, 249, 0.08));
border: 1rpx solid rgba(168, 85, 247, 0.24);
}
.wish-label {
display: block;
font-size: 22rpx;
color: #c186ff;
font-weight: 700;
letter-spacing: 2rpx;
margin-bottom: 8rpx;
}
.wish-text {
display: block;
font-size: 26rpx;
line-height: 1.62;
color: rgba(255, 255, 255, 0.92);
}
.stats {
display: grid;
grid-template-columns: repeat(3, 1fr);