v0.1.36a: 三问题修复——成员弹框双排名/界面白屏防线/推进异常取证+出险保障

【Bug2 双排名】MemberModal 顶部与 ModalShell 壳顶重复渲染 (title+category 各两排)
→ children 内嵌 title/cat 移除(壳已承载),改 mm-brief 一行(寿数/根骨)
【Bug3 定制白屏】App 无错误边界 → 全树崩溃只剩背景
→ AppErrorBoundary 一级防线(显示错误信息+重新加载按钮,不再白屏)
【Bug1 推进崩溃】advance 异常 toast 原文只写“已保存”——实为 Stash 静默吞错+双保险缺失
→ ①toast 显示根错前 120 字(玩家可见——此前只有 console) ②出险保存双保险:
Stash 失败时 localStorage 应急副本+明示“存储也失败”提示手动存档 ③speed timer 内 advance().catch 隔离
【验证】tsc 0 错/build 绿/7000 测试绿
This commit is contained in:
2026-08-24 21:53:04 +08:00
parent 293d04fc20
commit f5e49ef9bd
4 changed files with 50 additions and 10 deletions
+23
View File
@@ -12,6 +12,29 @@ import { startFxLayer, spawnBurst, stopFxLayer } from './ui/fx-canvas'
import { DriftLayer } from './ui/components/DriftLayer'
import { seasonOf } from './game/data/season'
import { Component, type ReactNode, type ErrorInfo } from 'react'
interface EBState { err: Error | null }
export class AppErrorBoundary extends Component<{ children: ReactNode }, EBState> {
state: EBState = { err: null }
static getDerivedStateFromError(err: Error): EBState { return { err } }
componentDidCatch(err: Error, info: ErrorInfo): void {
console.error('[ui-crash]', err, info.componentStack)
}
render(): ReactNode {
if (this.state.err) {
return (
<div style={{ padding: 32, color: '#e8d9b0', fontFamily: 'serif' }}>
<h2 style={{ color: '#d99a85' }}></h2>
<pre style={{ whiteSpace: 'pre-wrap', fontSize: '0.8rem', maxHeight: '50vh', overflow: 'auto' }}>{String(this.state.err?.message ?? this.state.err)}</pre>
<button className="btn" onClick={() => location.reload()}></button>
</div>
)
}
return this.props.children
}
}
export default function App() {
const screen = useGameStore((s) => s.screen)
const pendingEventId = useGameStore((s) => s.pendingEventId)