fix(label): inactivityTimer

This commit is contained in:
zhangheng
2026-04-21 20:18:33 +08:00
parent ea4daa4631
commit 8776ce4181

View File

@@ -49,11 +49,7 @@ import { useDescToolsStore } from "./useDescToolsStore"
import { useKeyboardStore } from "./useKeyBoardStore"
import { usePaperStore } from "./usePaperStore"
import { useRightToolsStore } from "./useRightToolsStore"
import {
useIntervalStore,
useLabelTimeStore,
useTimerStore,
} from "./useTimerStore"
import { useIntervalStore, useLabelTimeStore } from "./useTimerStore"
import { useTopToolsStore } from "./useTopToolsStore"
import { findGroupKey, isEditableKeyboardTarget } from "./util"
import { safeClone } from "./utils/clone"
@@ -89,6 +85,8 @@ const RIGHT_PANEL_SEPARATOR =
const RIGHT_PANEL_SOFT_MAIN_MIN_WIDTH = 420
const RIGHT_PANEL_HARD_MAIN_MIN_WIDTH = 260
const RIGHT_PANEL_TARGET_WIDTH = 350
const INACTIVITY_VIEW_DELAY_MS = 5 * 60 * 1000
const INACTIVITY_ACTIVITY_THROTTLE_MS = 1000
// utils
const getRectPoints = ([sx, sy, w, h]: number[]) => {
@@ -280,6 +278,8 @@ const LabelPage = ({
const topRef = useRef<any>(null)
const autoSaveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
const autoSaveInProgressRef = useRef(false)
const inactivityTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
const lastInactivityResetAtRef = useRef(0)
const paperContainerRef = useRef<any>(null)
const qaToolContainerRef = useRef<any>(null)
const [isConfirmSave, setIsConfirmSave] = useState(false)
@@ -2472,22 +2472,86 @@ const LabelPage = ({
}
}, [updateSplitterSizes])
useEffect(() => {
if (!isView) {
const delay = 5 * 60000
// 编辑模式下修改labelData时启动或更新定时器
useTimerStore.getState().startTimer(() => {
useTopToolsStore.getState().setIsView(true)
}, delay)
} else {
useTimerStore.getState().clearTimer()
const clearInactivityTimer = useCallback(() => {
if (inactivityTimerRef.current !== null) {
clearTimeout(inactivityTimerRef.current)
inactivityTimerRef.current = null
}
}, [])
const scheduleInactivityViewMode = useCallback(() => {
clearInactivityTimer()
inactivityTimerRef.current = setTimeout(() => {
const topToolsState = useTopToolsStore.getState()
if (!topToolsState.isView) {
topToolsState.setIsView(true)
}
}, INACTIVITY_VIEW_DELAY_MS)
}, [clearInactivityTimer])
const reportUserActivity = useCallback(
(force = false) => {
if (useTopToolsStore.getState().isView) return
const now = Date.now()
if (
!force &&
now - lastInactivityResetAtRef.current < INACTIVITY_ACTIVITY_THROTTLE_MS
) {
return
}
// 组件卸载时清理定时器
return () => {
useTimerStore.getState().clearTimer()
lastInactivityResetAtRef.current = now
scheduleInactivityViewMode()
},
[scheduleInactivityViewMode]
)
useEffect(() => {
if (isView) {
lastInactivityResetAtRef.current = 0
clearInactivityTimer()
return
}
}, [isView, labelData])
// 使用真实输入事件追踪活跃度,避免进行中的标注因 labelData 未变化被误判为空闲。
reportUserActivity(true)
const handlePointerDown = () => {
reportUserActivity(true)
}
const handlePointerMove = (event: PointerEvent) => {
if (event.buttons !== 0) {
reportUserActivity()
}
}
const handleWheel = () => {
reportUserActivity()
}
const handleKeyDown = () => {
reportUserActivity(true)
}
const handleVisibilityChange = () => {
if (document.visibilityState === "visible") {
reportUserActivity(true)
}
}
window.addEventListener("pointerdown", handlePointerDown, true)
window.addEventListener("pointermove", handlePointerMove, true)
window.addEventListener("wheel", handleWheel, true)
window.addEventListener("keydown", handleKeyDown, true)
document.addEventListener("visibilitychange", handleVisibilityChange)
return () => {
window.removeEventListener("pointerdown", handlePointerDown, true)
window.removeEventListener("pointermove", handlePointerMove, true)
window.removeEventListener("wheel", handleWheel, true)
window.removeEventListener("keydown", handleKeyDown, true)
document.removeEventListener("visibilitychange", handleVisibilityChange)
clearInactivityTimer()
}
}, [clearInactivityTimer, isView, reportUserActivity])
// auto save
useEffect(() => {