auto-save 2026-05-12 17:06 (+1, ~3)

This commit is contained in:
2026-05-12 17:06:43 +08:00
parent 4138bea9fa
commit 94afd6d644
4 changed files with 194 additions and 22 deletions

View File

@@ -14,6 +14,7 @@ import {
} from "@/components/nodes"
import { ThemeToggle } from "@/components/theme-toggle"
import { analyzeJob, createJob, getJob, uploadJob, type Job } from "@/lib/api"
import { FrameLightbox } from "@/components/lightbox"
const NODE_TYPES = {
input: InputNode,
@@ -64,6 +65,7 @@ export default function Home() {
const [submitting, setSubmitting] = useState(false)
const [analyzing, setAnalyzing] = useState(false)
const [selectedFrames, setSelectedFrames] = useState<Set<number>>(new Set())
const [expandedFrame, setExpandedFrame] = useState<number | null>(null)
const pollRef = useRef<ReturnType<typeof setInterval> | null>(null)
const handleSubmit = useCallback(async (url: string) => {
@@ -102,6 +104,8 @@ export default function Home() {
try {
await analyzeJob(job.id, 5)
toast.info("开始解析:拆轨 → 抽帧 → ASR → 翻译")
// 乐观更新本地状态,让轮询 useEffect 重新启动
setJob((prev) => prev ? { ...prev, status: "splitting", message: "拆轨中…", progress: 30 } : prev)
} catch (e) {
toast.error("解析触发失败:" + (e instanceof Error ? e.message : String(e)))
} finally {
@@ -118,6 +122,24 @@ export default function Home() {
})
}, [])
// URL ?job=xxx 自动恢复 job state
useEffect(() => {
const params = new URLSearchParams(window.location.search)
const id = params.get("job")
if (id && !job) {
getJob(id).then(setJob).catch(() => toast.error(`找不到 job ${id}`))
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
// 写回 URL不刷新页面
useEffect(() => {
if (!job) return
const url = new URL(window.location.href)
url.searchParams.set("job", job.id)
window.history.replaceState({}, "", url.toString())
}, [job?.id])
// 轮询 Jobdownloaded / transcribed / failed 三态停止)
useEffect(() => {
if (!job) return
@@ -144,6 +166,7 @@ export default function Home() {
onUploadFile: handleUpload,
onAnalyze: handleAnalyze,
onToggleFrame: handleToggleFrame,
onExpandFrame: setExpandedFrame,
}), [job, submitting, analyzing, selectedFrames, handleSubmit, handleUpload, handleAnalyze, handleToggleFrame])
// 用 useNodesState 让 ReactFlow 自己管位置(避免轮询时重置 drag
@@ -231,6 +254,19 @@ export default function Home() {
</footer>
<Toaster theme="system" position="top-right" />
{/* Lightbox 看大图 */}
{job && (
<FrameLightbox
jobId={job.id}
frames={job.frames}
activeIndex={expandedFrame}
selected={selectedFrames}
onClose={() => setExpandedFrame(null)}
onChange={setExpandedFrame}
onToggleSelect={handleToggleFrame}
/>
)}
</main>
</>
)