fix: useRowProgress 除零保护 + 组件卸载清理 + 补充smoke测试引用
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 15s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m14s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 2m0s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Successful in 18s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 45s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 2m30s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 58s
AI Code Review / AI Code Review (pull_request) Successful in 3m12s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 42s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 1m33s
ACR Cleanup / ACR Image Cleanup (pull_request_target) Successful in 35s
CI/CD Pipeline / PR Build Web Image (pull_request) Successful in 1m33s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 7m12s
CI/CD Pipeline / CI Gate (pull_request) Successful in 6s
CI/CD Pipeline / Production Browser E2E (pull_request) Failing after 1176h46m53s
CI/CD Pipeline / Canary Release to Production (pull_request) Failing after 1176h46m54s
CI/CD Pipeline / Build Production Web Image (pull_request) Failing after 1176h46m55s
CI/CD Pipeline / Build Production API Image (pull_request) Failing after 1176h46m55s
CI/CD Pipeline / Deploy Production (pull_request) Failing after 1176h46m54s
CI/CD Pipeline / Integration Tests (pull_request) Failing after 1176h46m56s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 1176h50m39s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 1176h50m41s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 1176h51m7s
CI/CD Pipeline / PR Build API Image (pull_request) Failing after 1176h51m24s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 1176h51m54s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 1176h53m52s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 1176h53m54s
CI/CD Pipeline / Build Production Worker Image (pull_request) Failing after 1177h19m55s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 1177h23m40s
CI/CD Pipeline / PR Build Worker Image (pull_request) Failing after 1177h24m9s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 1177h26m50s

This commit is contained in:
2026-07-29 13:45:52 +08:00
parent fac825b60b
commit 481a3ffc06
2 changed files with 34 additions and 4 deletions
@@ -1,4 +1,4 @@
import { useRef, useCallback } from "react"
import { useRef, useCallback, useEffect } from "react"
interface UseRowProgressOptions {
duration: number
@@ -7,6 +7,22 @@ interface UseRowProgressOptions {
export function useRowProgress({ duration, onSeek }: UseRowProgressOptions) {
const progressRef = useRef<HTMLDivElement>(null)
const listenersRef = useRef<{ move: ((e: MouseEvent) => void) | null; up: (() => void) | null }>({
move: null,
up: null,
})
const cleanupListeners = useCallback(() => {
const { move, up } = listenersRef.current
if (move) {
document.removeEventListener("mousemove", move)
listenersRef.current.move = null
}
if (up) {
document.removeEventListener("mouseup", up)
listenersRef.current.up = null
}
}, [])
const handleMouseDown = useCallback(
(e: React.MouseEvent<HTMLDivElement>) => {
@@ -16,6 +32,7 @@ export function useRowProgress({ duration, onSeek }: UseRowProgressOptions) {
const doSeek = (ev: MouseEvent) => {
if (!progressRef.current) return
const rect = progressRef.current.getBoundingClientRect()
if (rect.width <= 0) return
const percent = Math.max(0, Math.min(1, (ev.clientX - rect.left) / rect.width))
onSeek(percent * duration)
}
@@ -24,15 +41,26 @@ export function useRowProgress({ duration, onSeek }: UseRowProgressOptions) {
const handleMove = (ev: MouseEvent) => doSeek(ev)
const handleUp = () => {
document.removeEventListener("mousemove", handleMove)
document.removeEventListener("mouseup", handleUp)
cleanupListeners()
}
// 先清理旧的,再添加新的
cleanupListeners()
listenersRef.current.move = handleMove
listenersRef.current.up = handleUp
document.addEventListener("mousemove", handleMove)
document.addEventListener("mouseup", handleUp)
},
[duration, onSeek],
[duration, onSeek, cleanupListeners],
)
// 组件卸载时清理事件监听器
useEffect(() => {
return () => {
cleanupListeners()
}
}, [cleanupListeners])
return { progressRef, handleMouseDown }
}
@@ -20,6 +20,8 @@ import "@/pages/voice-materials/components/voice-material-card/CardActions"
import "@/pages/voice-materials/components/voice-material-card/BatchCheckbox"
import "@/pages/voice-materials/components/voice-material-card/types"
import "@/pages/voice-materials/components/VoiceMaterialRow"
import "@/pages/voice-materials/components/voice-material-row/useRowProgress"
import "@/pages/voice-materials/components/voice-material-row/TagDisplay"
import "@/pages/voice-materials/components/Toolbar"
import "@/pages/voice-materials/components/TagFilterBar"
import "@/pages/voice-materials/components/BatchBar"