feat: 全自动演出——开场自动进入/回复自动继续/终局台词演绎/已播行折叠(v2.1)
This commit is contained in:
@@ -43,10 +43,6 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="theater-actions">
|
||||
<view class="btn-primary theater-go" @click="finish">开始 ›</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -84,7 +80,8 @@ export default {
|
||||
mounted() {
|
||||
this.speaking = true
|
||||
speak(this.content, this.audio)
|
||||
setTimeout(() => { this.speaking = false }, Math.min(3000, this.content.length * 300))
|
||||
// v2.1:朗读结束自动进入决策幕(「跳过」仍可手动跳过)
|
||||
setTimeout(() => { this.speaking = false; this.$emit('done') }, Math.min(3000, this.content.length * 300))
|
||||
},
|
||||
beforeUnmount() {
|
||||
stopSpeak()
|
||||
@@ -126,6 +123,4 @@ export default {
|
||||
@keyframes t-word { 0% { opacity: 0; transform: translateY(12rpx); } 100% { opacity: 1; transform: translateY(0); } }
|
||||
.theater-py { font-size: 20rpx; color: #ff6b35; line-height: 1.3; height: 28rpx; }
|
||||
.theater-ch { font-size: 34rpx; line-height: 1.5; color: #5b4636; }
|
||||
.theater-actions { display: flex; justify-content: center; margin-top: 32rpx; position: relative; z-index: 2; }
|
||||
.theater-go { font-size: 34rpx; min-width: 240rpx; animation: t-pop 0.5s ease 1.2s backwards; }
|
||||
</style>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
</view>
|
||||
|
||||
<view class="story-lines">
|
||||
<view v-for="(line, i) in script" :key="i" class="story-line" :class="{ active: i === lineIndex, done: i < lineIndex }">
|
||||
<view v-for="(line, i) in script" :key="i" v-show="i === lineIndex || i === lineIndex - 1" class="story-line" :class="{ active: i === lineIndex, fading: i === lineIndex - 1 }">
|
||||
<view v-if="line.speaker === '旁白'" class="bubble nar-bubble">
|
||||
<view class="bubble-name">📖 旁白</view>
|
||||
<RubyText :text="line.text" :pinyin="line.pinyin || ''" :show="showPinyin" :highlight="i === lineIndex ? charIndex : -1" />
|
||||
@@ -136,7 +136,7 @@ export default {
|
||||
.story-lines { display: flex; flex-direction: column; gap: 24rpx; padding-bottom: 24rpx; }
|
||||
.story-line { opacity: 0; transition: opacity 0.4s; }
|
||||
.story-line.active { opacity: 1; }
|
||||
.story-line.done { opacity: 0.55; }
|
||||
.story-line.fading { opacity: 0.35; }
|
||||
.bubble { border-radius: 24rpx; padding: 24rpx 28rpx; box-shadow: 0 4rpx 16rpx rgba(91, 70, 54, 0.08); }
|
||||
.bubble-name { font-size: 24rpx; font-weight: 700; color: #ff6b35; margin-bottom: 8rpx; }
|
||||
.nar-bubble { background: #fff3d6; margin-left: 40rpx; margin-right: 40rpx; }
|
||||
|
||||
@@ -45,6 +45,11 @@
|
||||
<SpeakButton class="scene-speak" :text="detail.scene_content" :file="detail.scene_audio" label="读一读情境" />
|
||||
</view>
|
||||
|
||||
<!-- v2.1 终局演绎:结局台词播完自动跳结算 -->
|
||||
<view v-if="playingFinal && finalNode" class="node story-node final-story">
|
||||
<StoryPlayer :key="'final-' + finalNode.node_id" :script="finalScript" :character="finalNode.character" :show-pinyin="showPinyin" @done="gotoResult" />
|
||||
</view>
|
||||
|
||||
<!-- 节点:剧情流(script 非空)或 v1 卡片(回退) -->
|
||||
<view v-if="curNode && isStoryNode" class="node story-node">
|
||||
<StoryPlayer :key="curNode.node_id" :script="storyScript" :character="curNode.character" :show-pinyin="showPinyin" @done="showOptions = true" />
|
||||
@@ -170,7 +175,10 @@ export default {
|
||||
soundOn: isSoundEnabled(),
|
||||
showIntro: false,
|
||||
sceneFx: '',
|
||||
branchTimer: null
|
||||
branchTimer: null,
|
||||
replyTimer: null,
|
||||
playingFinal: false,
|
||||
finalNode: null
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
@@ -179,6 +187,7 @@ export default {
|
||||
},
|
||||
onUnload() {
|
||||
if (this.branchTimer) clearTimeout(this.branchTimer)
|
||||
if (this.replyTimer) clearTimeout(this.replyTimer)
|
||||
},
|
||||
computed: {
|
||||
scene() {
|
||||
@@ -207,6 +216,9 @@ export default {
|
||||
},
|
||||
introProps() {
|
||||
return this.detail ? entryProps(this.detail.entry) : []
|
||||
},
|
||||
finalScript() {
|
||||
return this.finalNode ? parseScript(this.finalNode.script) : null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -266,6 +278,8 @@ export default {
|
||||
if (this.isStoryNode) {
|
||||
this.reply = fb
|
||||
this.showOptions = false // 提交后隐藏选项区,防重复点击
|
||||
// v2.1:回应气泡约 3 秒自动继续(点击「继续」立即继续)
|
||||
this.replyTimer = setTimeout(() => this.autoContinue(), 3000)
|
||||
} else {
|
||||
this.feedback = fb
|
||||
}
|
||||
@@ -279,8 +293,15 @@ export default {
|
||||
route_steps: this.routeSteps,
|
||||
final: data.final
|
||||
})
|
||||
playSound('finish')
|
||||
uni.redirectTo({ url: '/pages/result/result' })
|
||||
this.choosing = false
|
||||
// v2.1:终局节点有剧本 → 先演绎结局台词再跳结算;无剧本直接跳(回退)
|
||||
if (data.final.final_node && parseScript(data.final.final_node.script)) {
|
||||
this.finalNode = data.final.final_node
|
||||
this.playingFinal = true
|
||||
} else {
|
||||
playSound('finish')
|
||||
uni.redirectTo({ url: '/pages/result/result' })
|
||||
}
|
||||
} else {
|
||||
this.choosing = false
|
||||
}
|
||||
@@ -288,7 +309,15 @@ export default {
|
||||
this.choosing = false
|
||||
}
|
||||
},
|
||||
autoContinue() {
|
||||
if (this.reply && !this.choosing) this.continuePlay()
|
||||
},
|
||||
gotoResult() {
|
||||
playSound('finish')
|
||||
uni.redirectTo({ url: '/pages/result/result' })
|
||||
},
|
||||
continuePlay() {
|
||||
if (this.replyTimer) { clearTimeout(this.replyTimer); this.replyTimer = null }
|
||||
if (this.isStoryNode) {
|
||||
this.curNode = this.reply.next
|
||||
this.reply = null
|
||||
|
||||
Reference in New Issue
Block a user