auto-save 2026-05-12 17:06 (+1, ~3)
This commit is contained in:
@@ -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])
|
||||
|
||||
// 轮询 Job(downloaded / 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>
|
||||
</>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user