diff --git a/client/src/lib/changelog.ts b/client/src/lib/changelog.ts index 650bc29..3253175 100644 --- a/client/src/lib/changelog.ts +++ b/client/src/lib/changelog.ts @@ -8,6 +8,22 @@ export type ChangeLogEntry = { }; export const CHANGE_LOG_ENTRIES: ChangeLogEntry[] = [ + { + version: "2026.03.15-live-analysis-leave-hint", + releaseDate: "2026-03-15", + repoVersion: "pending-commit", + summary: "实时分析结束后增加离开提示,明确何时必须停留、何时可以安全关闭或切页。", + features: [ + "分析进行中显示“不要关闭或切走页面”提示", + "结束分析后保存阶段显示“请暂时停留当前页面”提示", + "保存成功后明确提示“现在可以关闭浏览器或切换到其他页面”", + "分析中和保存中挂接 beforeunload 提醒,减少误关页面导致的数据丢失", + ], + tests: [ + "pnpm check", + "pnpm build", + ], + }, { version: "2026.03.15-training-generator-collapse", releaseDate: "2026-03-15", diff --git a/client/src/pages/LiveCamera.tsx b/client/src/pages/LiveCamera.tsx index 2b51bb7..dcb637f 100644 --- a/client/src/pages/LiveCamera.tsx +++ b/client/src/pages/LiveCamera.tsx @@ -1,5 +1,6 @@ import { useAuth } from "@/_core/hooks/useAuth"; import { trpc } from "@/lib/trpc"; +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; @@ -572,6 +573,7 @@ export default function LiveCamera() { const [sessionMode, setSessionMode] = useState("practice"); const [analyzing, setAnalyzing] = useState(false); const [saving, setSaving] = useState(false); + const [leaveStatus, setLeaveStatus] = useState<"idle" | "analyzing" | "saving" | "safe" | "failed">("idle"); const [immersivePreview, setImmersivePreview] = useState(false); const [liveScore, setLiveScore] = useState(null); const [currentAction, setCurrentAction] = useState("unknown"); @@ -979,6 +981,7 @@ export default function LiveCamera() { analyzingRef.current = true; setAnalyzing(true); setSaving(false); + setLeaveStatus("analyzing"); setSegments([]); segmentsRef.current = []; currentSegmentRef.current = null; @@ -1049,6 +1052,7 @@ export default function LiveCamera() { } catch (error: any) { analyzingRef.current = false; setAnalyzing(false); + setLeaveStatus("idle"); await stopSessionRecorder(); toast.error(`实时分析启动失败: ${error?.message || "未知错误"}`); } @@ -1059,6 +1063,7 @@ export default function LiveCamera() { analyzingRef.current = false; setAnalyzing(false); setSaving(true); + setLeaveStatus("saving"); if (animationRef.current) { cancelAnimationFrame(animationRef.current); @@ -1071,15 +1076,32 @@ export default function LiveCamera() { poseRef.current = null; } await persistSession(); + setLeaveStatus("safe"); toast.success("实时分析已保存,并同步写入训练记录"); await liveSessionsQuery.refetch(); } catch (error: any) { + setLeaveStatus("failed"); toast.error(`保存实时分析失败: ${error?.message || "未知错误"}`); } finally { setSaving(false); } }, [liveSessionsQuery, persistSession]); + useEffect(() => { + if (!analyzing && !saving) { + return; + } + + const handleBeforeUnload = (event: BeforeUnloadEvent) => { + event.preventDefault(); + event.returnValue = "实时分析数据仍在处理中,请先等待保存完成。"; + return event.returnValue; + }; + + window.addEventListener("beforeunload", handleBeforeUnload); + return () => window.removeEventListener("beforeunload", handleBeforeUnload); + }, [analyzing, saving]); + const handleSetupComplete = useCallback(async () => { setShowSetupGuide(false); await startCamera(facing, zoomTargetRef.current, qualityPreset); @@ -1217,6 +1239,46 @@ export default function LiveCamera() { + {leaveStatus === "analyzing" ? ( + + + 分析进行中 + + 当前仍在采集和识别动作数据,请先不要关闭浏览器或切走页面。 + + + ) : null} + + {leaveStatus === "saving" ? ( + + + 正在保存分析结果 + + 视频、动作区间和训练记录正在提交,请暂时停留当前页面;保存完成后会提示你可以离开。 + + + ) : null} + + {leaveStatus === "safe" ? ( + + + 分析结果已保存 + + 当前分析数据已经提交完成。现在可以关闭浏览器、返回上一页,或切换到其他页面,不会影响已保存的数据。 + + + ) : null} + + {leaveStatus === "failed" ? ( + + + 分析保存失败 + + 当前会话还没有完整写入,请先留在本页并重新尝试结束分析或检查网络状态。 + + + ) : null} +
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 3b52621..5430827 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,23 @@ # Tennis Training Hub - 变更日志 +## 2026.03.15-live-analysis-leave-hint (2026-03-15) + +### 功能更新 + +- 实时分析进行中显示“不要关闭浏览器或切走页面”提示 +- 点击“结束分析”后,保存阶段显示“请暂时停留当前页面”提示 +- 保存完成后明确提示“现在可以关闭浏览器或切换到其他页面” +- 分析中和保存中增加离开页面提醒,减少误关导致的数据丢失 + +### 测试 + +- `pnpm check` +- `pnpm build` + +### 仓库版本 + +- `pending-commit` + ## 2026.03.15-training-generator-collapse (2026-03-15) ### 功能更新