fix: NIT 合并——开场朗读 onEnd 驱动自动进入(防 3s 截断)/continuePlay 空守卫/gotoResult 防双跳/计时器卸载清理
This commit is contained in:
@@ -1378,9 +1378,12 @@ git add ui-src/src/components/SceneTheater.vue ui-src/src/components/StoryPlayer
|
|||||||
git commit -m "feat: 全自动演出——开场自动进入/回复自动继续/终局台词演绎/已播行折叠(v2.1)"
|
git commit -m "feat: 全自动演出——开场自动进入/回复自动继续/终局台词演绎/已播行折叠(v2.1)"
|
||||||
```
|
```
|
||||||
|
|
||||||
> 审查记录(0f8a371 审查员 1 APPROVE + 1 SHOULD-FIX):
|
> 审查记录(0f8a371 双审查 APPROVE + d571e89 SHOULD-FIX + NIT 合并提交):
|
||||||
> - SHOULD-FIX(已修):终局演绎块与剧情流块是并列 v-if 而非互斥——终局播放期间 `curNode && isStoryNode` 仍为 true,旧节点块(已播行 + ActionCard,choosing=false 时可点击)残留可见可交互。修复:剧情流块与 v1 卡片块加 `!playingFinal` 守卫,三块互斥。
|
> - SHOULD-FIX(已修):终局演绎块与剧情流块是并列 v-if 而非互斥——终局播放期间 `curNode && isStoryNode` 仍为 true,旧节点块(已播行 + ActionCard,choosing=false 时可点击)残留可见可交互。修复:剧情流块与 v1 卡片块加 `!playingFinal` 守卫,三块互斥。
|
||||||
> - NIT(记录):SceneTheater 3s 上限会截断长音频朗读(v1 既有公式,自动推进后更易暴露);终局长台词由 StoryPlayer MAX_LINE_MS 兜底,无需改
|
> - NIT1(已修):continuePlay 无空守卫,点击与 3s 自动同帧时 reply/feedback 为 null 抛 TypeError → 开头加 `if (!this.reply && !this.feedback) return`
|
||||||
|
> - NIT2(已修):SceneTheater 开场计时器不随卸载清理,跳过后残留 done 触发 → minTimer/autoTimer 存字段,beforeUnmount 清理
|
||||||
|
> - NIT3(已修):开场朗读 3s 上限必然截断长文本(30 字约 8-12s 朗读被砍)→ 改 speak onEnd 驱动自动进入(最短展示 1.2s 防无 TTS 闪退,15s 兜底防 onEnd 缺失卡死)
|
||||||
|
> - NIT4(已修):终局 StoryPlayer done 与「跳过」双触发 gotoResult → doneJumped 一次性守卫
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -79,11 +79,32 @@ export default {
|
|||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.speaking = true
|
this.speaking = true
|
||||||
speak(this.content, this.audio)
|
// v2.1:朗读结束自动进入决策幕——最短展示 1.2s,之后 speak onEnd 即进入;
|
||||||
// v2.1:朗读结束自动进入决策幕(「跳过」仍可手动跳过)
|
// 无 TTS/onEnd 缺失最迟 15s 兜底(「跳过」仍可手动跳过)
|
||||||
setTimeout(() => { this.speaking = false; this.$emit('done') }, Math.min(3000, this.content.length * 300))
|
this.speechDone = false
|
||||||
|
this.ready = false
|
||||||
|
let done = false
|
||||||
|
const finishAuto = () => {
|
||||||
|
if (done) return
|
||||||
|
done = true
|
||||||
|
this.speaking = false
|
||||||
|
this.$emit('done')
|
||||||
|
}
|
||||||
|
this.minTimer = setTimeout(() => { this.ready = true; if (this.speechDone) finishAuto() }, 1200)
|
||||||
|
this.autoTimer = setTimeout(finishAuto, 15000)
|
||||||
|
const onSpeechEnd = () => {
|
||||||
|
this.speechDone = true
|
||||||
|
if (this.ready) finishAuto()
|
||||||
|
}
|
||||||
|
if (!this.content) {
|
||||||
|
finishAuto()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
speak(this.content, this.audio, onSpeechEnd)
|
||||||
},
|
},
|
||||||
beforeUnmount() {
|
beforeUnmount() {
|
||||||
|
clearTimeout(this.minTimer)
|
||||||
|
clearTimeout(this.autoTimer)
|
||||||
stopSpeak()
|
stopSpeak()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@@ -178,7 +178,8 @@ export default {
|
|||||||
branchTimer: null,
|
branchTimer: null,
|
||||||
replyTimer: null,
|
replyTimer: null,
|
||||||
playingFinal: false,
|
playingFinal: false,
|
||||||
finalNode: null
|
finalNode: null,
|
||||||
|
doneJumped: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onLoad(options) {
|
onLoad(options) {
|
||||||
@@ -298,6 +299,7 @@ export default {
|
|||||||
if (data.final.final_node && parseScript(data.final.final_node.script)) {
|
if (data.final.final_node && parseScript(data.final.final_node.script)) {
|
||||||
this.finalNode = data.final.final_node
|
this.finalNode = data.final.final_node
|
||||||
this.playingFinal = true
|
this.playingFinal = true
|
||||||
|
this.doneJumped = false
|
||||||
} else {
|
} else {
|
||||||
playSound('finish')
|
playSound('finish')
|
||||||
uni.redirectTo({ url: '/pages/result/result' })
|
uni.redirectTo({ url: '/pages/result/result' })
|
||||||
@@ -313,11 +315,14 @@ export default {
|
|||||||
if (this.reply && !this.choosing) this.continuePlay()
|
if (this.reply && !this.choosing) this.continuePlay()
|
||||||
},
|
},
|
||||||
gotoResult() {
|
gotoResult() {
|
||||||
|
if (this.doneJumped) return // 防重复跳转(done 与跳过双触发)
|
||||||
|
this.doneJumped = true
|
||||||
playSound('finish')
|
playSound('finish')
|
||||||
uni.redirectTo({ url: '/pages/result/result' })
|
uni.redirectTo({ url: '/pages/result/result' })
|
||||||
},
|
},
|
||||||
continuePlay() {
|
continuePlay() {
|
||||||
if (this.replyTimer) { clearTimeout(this.replyTimer); this.replyTimer = null }
|
if (this.replyTimer) { clearTimeout(this.replyTimer); this.replyTimer = null }
|
||||||
|
if (!this.reply && !this.feedback) return // 空守卫:点击与 3s 自动同帧时防 TypeError
|
||||||
if (this.isStoryNode) {
|
if (this.isStoryNode) {
|
||||||
this.curNode = this.reply.next
|
this.curNode = this.reply.next
|
||||||
this.reply = null
|
this.reply = null
|
||||||
|
|||||||
Reference in New Issue
Block a user