Add leave-state hints for live analysis
这个提交包含在:
@@ -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",
|
||||
|
||||
@@ -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<SessionMode>("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<PoseScore | null>(null);
|
||||
const [currentAction, setCurrentAction] = useState<ActionType>("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() {
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{leaveStatus === "analyzing" ? (
|
||||
<Alert>
|
||||
<Activity className="h-4 w-4" />
|
||||
<AlertTitle>分析进行中</AlertTitle>
|
||||
<AlertDescription>
|
||||
当前仍在采集和识别动作数据,请先不要关闭浏览器或切走页面。
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
) : null}
|
||||
|
||||
{leaveStatus === "saving" ? (
|
||||
<Alert>
|
||||
<Activity className="h-4 w-4" />
|
||||
<AlertTitle>正在保存分析结果</AlertTitle>
|
||||
<AlertDescription>
|
||||
视频、动作区间和训练记录正在提交,请暂时停留当前页面;保存完成后会提示你可以离开。
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
) : null}
|
||||
|
||||
{leaveStatus === "safe" ? (
|
||||
<Alert>
|
||||
<CheckCircle2 className="h-4 w-4" />
|
||||
<AlertTitle>分析结果已保存</AlertTitle>
|
||||
<AlertDescription>
|
||||
当前分析数据已经提交完成。现在可以关闭浏览器、返回上一页,或切换到其他页面,不会影响已保存的数据。
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
) : null}
|
||||
|
||||
{leaveStatus === "failed" ? (
|
||||
<Alert>
|
||||
<Activity className="h-4 w-4" />
|
||||
<AlertTitle>分析保存失败</AlertTitle>
|
||||
<AlertDescription>
|
||||
当前会话还没有完整写入,请先留在本页并重新尝试结束分析或检查网络状态。
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
) : null}
|
||||
|
||||
<section className="rounded-[28px] border border-border/60 bg-[radial-gradient(circle_at_top_left,_rgba(249,115,22,0.16),_transparent_32%),linear-gradient(135deg,rgba(12,18,24,0.98),rgba(26,31,43,0.96))] p-5 text-white shadow-xl shadow-black/10 md:p-7">
|
||||
<div className="flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between">
|
||||
<div className="space-y-3">
|
||||
|
||||
在新工单中引用
屏蔽一个用户