perf(timer): perf

This commit is contained in:
2026-03-04 16:00:20 +08:00
parent b3cdaa960e
commit 2402d685d7
8 changed files with 146 additions and 69 deletions

View File

@@ -48,7 +48,11 @@ import { useDescToolsStore } from "./useDescToolsStore"
import { useKeyboardStore } from "./useKeyBoardStore"
import { usePaperStore } from "./usePaperStore"
import { useRightToolsStore } from "./useRightToolsStore"
import { useIntervalStore, useTimerStore } from "./useTimerStore"
import {
useIntervalStore,
useLabelTimeStore,
useTimerStore,
} from "./useTimerStore"
import { useTopToolsStore } from "./useTopToolsStore"
import { findGroupKey } from "./util"
import { safeClone } from "./utils/clone"
@@ -157,19 +161,20 @@ const LabelPage = ({
// Project.LabelSchemaList[]
// >([]);
const topRef = useRef<any>(null)
const autoSaveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
const autoSaveInProgressRef = useRef(false)
const paperContainerRef = useRef<any>(null)
const qaToolContainerRef = useRef<any>(null)
const [isConfirmSave, setIsConfirmSave] = useState(false)
const [loading, setLoading] = useState(false)
const [sizes, setSizes] = useState<number[]>([])
const {
label: labelData,
setLabel,
setStateStack,
setLabelTime,
} = useLabelStore()
const { isAutoSave, autoSaveGap } = useIntervalStore()
const labelData = useLabelStore((state) => state.label)
const setLabel = useLabelStore((state) => state.setLabel)
const setStateStack = useLabelStore((state) => state.setStateStack)
const setLabelTime = useLabelTimeStore((state) => state.setLabelTime)
const isAutoSave = useIntervalStore((state) => state.isAutoSave)
const autoSaveGap = useIntervalStore((state) => state.autoSaveGap)
const {
editMode,
@@ -1310,17 +1315,40 @@ const LabelPage = ({
// auto save
useEffect(() => {
if (isAutoSave && !isView) {
const minute = 60 * 1000
useIntervalStore.getState().startTimer(() => {
topRef.current.handleSave()
}, autoSaveGap * minute)
} else {
useIntervalStore.getState().clearTimer()
let cancelled = false
if (autoSaveTimerRef.current !== null) {
clearTimeout(autoSaveTimerRef.current)
autoSaveTimerRef.current = null
}
if (!isAutoSave || isView) return
const minute = 60 * 1000
const delay = autoSaveGap * minute
const scheduleNext = () => {
autoSaveTimerRef.current = setTimeout(async () => {
if (cancelled) return
if (autoSaveInProgressRef.current) {
scheduleNext()
return
}
autoSaveInProgressRef.current = true
try {
await topRef.current?.handleSave?.()
} catch (error) {
console.error("[LabelNossr] auto save failed", error)
} finally {
autoSaveInProgressRef.current = false
if (!cancelled) scheduleNext()
}
}, delay)
}
scheduleNext()
return () => {
useIntervalStore.getState().clearTimer()
cancelled = true
if (autoSaveTimerRef.current !== null) {
clearTimeout(autoSaveTimerRef.current)
autoSaveTimerRef.current = null
}
}
}, [autoSaveGap, isAutoSave, isView])

View File

@@ -29,6 +29,7 @@ import { useDescToolsStore } from "../useDescToolsStore"
import { useKeyboardStore } from "../useKeyBoardStore"
import { useOtherToolsStore } from "../useOtherToolsStore"
import { usePaperStore } from "../usePaperStore"
import { useLabelTimeStore } from "../useTimerStore"
import { useTopToolsStore } from "../useTopToolsStore"
import { getSubAttrStatus } from "../util"
import { safeClone } from "../utils/clone"
@@ -50,7 +51,9 @@ const BottomTools: React.FC<BottomToolsComponentProps> = (props) => {
const itemRefs = useRef<Record<string, HTMLDivElement | null>>({})
const { label: storeLabel, setLabel, pushStateStack } = useLabelStore()
const storeLabel = useLabelStore((state) => state.label)
const setLabel = useLabelStore((state) => state.setLabel)
const pushStateStack = useLabelStore((state) => state.pushStateStack)
const {
inputNumber,
setInputNumber,
@@ -521,17 +524,16 @@ const BottomTools: React.FC<BottomToolsComponentProps> = (props) => {
review2_uid: 0,
}
data.key_frame = true
const currentLabelTime =
useLabelTimeStore.getState().labelTime
if (taskDetail.label_status === 2) {
data.label1_ts =
useLabelStore.getState().labelTime.label
data.label1_ts = currentLabelTime.label
data.label1_uid = usePermissionStore.getState().user_id
} else if (taskDetail.label_status === 4) {
data.review1_ts =
useLabelStore.getState().labelTime.review1
data.review1_ts = currentLabelTime.review1
data.review1_uid = usePermissionStore.getState().user_id
} else if (taskDetail.label_status === 6) {
data.review2_ts =
useLabelStore.getState().labelTime.review2
data.review2_ts = currentLabelTime.review2
data.review2_uid = usePermissionStore.getState().user_id
}
setKeyFrameData(activeImage, data)

View File

@@ -159,12 +159,12 @@ const PaperContainer = (
const { activeImage } = useBottomToolsStore()
const {
label: storeLabel,
deleteOperation,
setOperation,
getLabelDetailDataByKeys,
} = useLabelStore()
const storeLabel = useLabelStore((state) => state.label)
const deleteOperation = useLabelStore((state) => state.deleteOperation)
const setOperation = useLabelStore((state) => state.setOperation)
const getLabelDetailDataByKeys = useLabelStore(
(state) => state.getLabelDetailDataByKeys
)
const {
objectOperations,

View File

@@ -49,7 +49,8 @@ const RightGroupTools: React.FC<RightGroupToolsComponentProps> = (props) => {
},
[projectDetail?.label_schema_list]
)
const { setLabel, pushStateStack } = useLabelStore()
const setLabel = useLabelStore((state) => state.setLabel)
const pushStateStack = useLabelStore((state) => state.pushStateStack)
const { pathGroupMap, groupPathVisible, setGroupPathVisible } =
useRightToolsStore()
const { activeImage } = useBottomToolsStore()

View File

@@ -78,7 +78,7 @@ export const renderOperationIcon = (
const RightObjectTools: React.FC<RightObjectToolsComponentProps> = (props) => {
const { labelState, projectDetail, taskDetail } = props
const { label: storeLabel } = useLabelStore()
const storeLabel = useLabelStore((state) => state.label)
const { activeImage } = useBottomToolsStore()

View File

@@ -89,7 +89,7 @@ import { useBottomToolsStore } from "../useBottomToolsStore"
import { useDescToolsStore } from "../useDescToolsStore"
import { usePaperStore } from "../usePaperStore"
import { useRightToolsStore } from "../useRightToolsStore"
import { useIntervalStore } from "../useTimerStore"
import { useIntervalStore, useLabelTimeStore } from "../useTimerStore"
import { useTopToolsStore } from "../useTopToolsStore"
import { getSubAttrStatus } from "../util"
import { labelTypeMap, TaskStatusEnum } from "../utils/constants"
@@ -133,6 +133,17 @@ const initialWorkLoad: WorkLoad = {
question_size: {},
}
const TaskTimerDisplay = ({
currentTimeKey,
}: {
currentTimeKey: "label" | "review1" | "review2"
}) => {
const currentTime = useLabelTimeStore(
(state) => state.labelTime[currentTimeKey]
)
return <>{dayjs.duration(currentTime, "seconds").format("HH:mm:ss")}</>
}
const TopTools = (
props: TopToolsComponentProps,
ref: React.Ref<unknown> | undefined
@@ -157,13 +168,10 @@ const TopTools = (
const [duplicateName, setDuplicateName] = useState("")
const [recoverOpen, setRecoverOpen] = useState(false)
const [taskOpen, setTaskOpen] = useState(false)
const {
label: labelData,
setLabel,
labelTime,
setLabelTime,
pushStateStack,
} = useLabelStore()
const labelData = useLabelStore((state) => state.label)
const setLabel = useLabelStore((state) => state.setLabel)
const pushStateStack = useLabelStore((state) => state.pushStateStack)
const setLabelTime = useLabelTimeStore((state) => state.setLabelTime)
const { activeImage } = useBottomToolsStore()
const {
isView,
@@ -212,8 +220,10 @@ const TopTools = (
} = useTopToolsStore()
const { pathGroupMap } = useRightToolsStore()
const { isAutoSave, setIsAutoSave, autoSaveGap, setAutoSaveGap } =
useIntervalStore()
const isAutoSave = useIntervalStore((state) => state.isAutoSave)
const setIsAutoSave = useIntervalStore((state) => state.setIsAutoSave)
const autoSaveGap = useIntervalStore((state) => state.autoSaveGap)
const setAutoSaveGap = useIntervalStore((state) => state.setAutoSaveGap)
// 当前是否可以操作功能按键
const currentEditAuth = useMemo(() => {
@@ -723,10 +733,11 @@ const TopTools = (
}
}
const currentLabelTime = useLabelTimeStore.getState().labelTime
const workTime = {
label_work_time: labelTime.label,
first_review_work_time: labelTime.review1,
second_review_work_time: labelTime.review2,
label_work_time: currentLabelTime.label,
first_review_work_time: currentLabelTime.review1,
second_review_work_time: currentLabelTime.review2,
}
// 生成新workload
let time = 0
@@ -851,9 +862,6 @@ const TopTools = (
}
}, [
labelCategories,
labelTime.label,
labelTime.review1,
labelTime.review2,
oldWorkLoad,
pathGroupMap,
projectDetail,
@@ -1257,22 +1265,23 @@ const TopTools = (
console.log(error)
return
}
const currentLabelTime = useLabelTimeStore.getState().labelTime
const handleAction = (current_status: number) => {
switch (current_status) {
case 2:
return {
commit_action: key || 1,
work_time: labelTime.label,
work_time: currentLabelTime.label,
}
case 4:
return {
commit_action: key || 2,
work_time: labelTime.review1,
work_time: currentLabelTime.review1,
}
case 6:
return {
commit_action: key || 3,
work_time: labelTime.review2,
work_time: currentLabelTime.review2,
}
default:
return {
@@ -1345,15 +1354,15 @@ const TopTools = (
useEffect(() => {
let timer = setInterval(() => {
if (isView) return
setLabelTime({
...labelTime,
[currentTimeKey]: labelTime[currentTimeKey] + 1,
})
setLabelTime((prev) => ({
...prev,
[currentTimeKey]: prev[currentTimeKey] + 1,
}))
}, 1000)
return () => {
clearInterval(timer)
}
}, [currentTimeKey, isView, labelTime, setLabelTime])
}, [currentTimeKey, isView, setLabelTime])
const form = useForm({
initialValues: {
@@ -1748,9 +1757,7 @@ const TopTools = (
{isLabelTask && (
<Flex justify="space-between" align="center" gap="md" px="md">
<Timer style={{ width: 20, height: 20 }} />
{dayjs
.duration(labelTime[currentTimeKey], "seconds")
.format("HH:mm:ss")}
<TaskTimerDisplay currentTimeKey={currentTimeKey} />
</Flex>
)}
<Flex justify="flex-end" align="center" gap="md" px="0" flex={1}>

View File

@@ -7,6 +7,11 @@ import { safeClone } from "./utils/clone"
type LabelData = Map<string, Map<string, [number, any[], any, any[]][]>>
type LabelPathTuple = [number, any[], any, any[]]
type LabelTime = {
label: number
review1: number
review2: number
}
const isPaperPointLike = (value: any) => {
return (
@@ -53,11 +58,7 @@ const normalizeLabelPathTuple = (path: LabelPathTuple): LabelPathTuple => {
interface LabelState {
// pathId pathPoints detail hollowPathPoints
label: LabelData
labelTime: {
label: number
review1: number
review2: number
}
labelTime: LabelTime
labelDefaultComments: Comment[]
setLabel: (label: LabelData) => void
stateStack: LabelData[]
@@ -83,11 +84,9 @@ interface LabelState {
[keys: string]: any
}
) => void
setLabelTime: (labelTime: {
label: number
review1: number
review2: number
}) => void
setLabelTime: (
labelTime: LabelTime | ((prev: LabelTime) => LabelTime)
) => void
setLabelDefaultComments: (arr: Comment[]) => void
setImage: (
imageId: string,
@@ -312,7 +311,10 @@ export const useLabelStore = create(
storeSet((state) => {
return {
...state,
labelTime,
labelTime:
typeof labelTime === "function"
? labelTime(state.labelTime)
: labelTime,
}
}),
setLabelDefaultComments: (labelDefaultComments) =>

View File

@@ -65,3 +65,40 @@ export const useIntervalStore = create<IntervalStore>((set, get) => ({
set((state) => ({ ...state, autoSaveGap: value }))
},
}))
export interface LabelTimeState {
label: number
review1: number
review2: number
}
interface LabelTimeStore {
labelTime: LabelTimeState
setLabelTime: (
labelTime: LabelTimeState | ((prev: LabelTimeState) => LabelTimeState)
) => void
resetLabelTime: () => void
}
const initialLabelTimeState: LabelTimeState = {
label: 0,
review1: 0,
review2: 0,
}
export const useLabelTimeStore = create<LabelTimeStore>((set) => ({
labelTime: initialLabelTimeState,
setLabelTime: (labelTime) =>
set((state) => ({
...state,
labelTime:
typeof labelTime === "function"
? labelTime(state.labelTime)
: labelTime,
})),
resetLabelTime: () =>
set((state) => ({
...state,
labelTime: initialLabelTimeState,
})),
}))