From 853801b94780092ce50f796dac48d2068b63a2b5 Mon Sep 17 00:00:00 2001 From: zhangheng Date: Mon, 20 Apr 2026 20:10:05 +0800 Subject: [PATCH] fix(tool): right object --- .../label/components/RightObjectTools.tsx | 167 +++++++++++------- components/label/components/TopTools.tsx | 38 +++- 2 files changed, 137 insertions(+), 68 deletions(-) diff --git a/components/label/components/RightObjectTools.tsx b/components/label/components/RightObjectTools.tsx index cb1509e..5770106 100644 --- a/components/label/components/RightObjectTools.tsx +++ b/components/label/components/RightObjectTools.tsx @@ -8,8 +8,8 @@ import { Collapse, Flex, Group, + HoverCard, Paper, - Popover, ScrollArea, Stack, Text, @@ -31,6 +31,7 @@ import { } from "lucide-react" import paper from "paper" import { useCallback, useMemo, useState } from "react" +import { Comment } from "../api/label/typing" import { Project } from "../api/project/typing" import { Task } from "../api/task/typing" import { LabelState } from "../LabelNossr" @@ -141,6 +142,65 @@ const RightObjectTools: React.FC = (props) => { } }, []) + const getCommentTextColor = useCallback((type: number) => { + switch (type) { + case 3: + return "yellow.9" + case 2: + return "red.7" + case 1: + return "green.7" + case 0: + return "gray.7" + default: + return "blue.7" + } + }, []) + + const getUserLabel = useCallback( + (uid?: number) => { + if (uid === undefined || uid === null) return "-" + return ( + userOpts.find((item) => item.value === uid)?.label || uid.toString() + ) + }, + [userOpts] + ) + + const getCommentCount = useCallback((commentItem: Comment) => { + const checkBoxComments = (commentItem.check_box_comments || []).filter( + (item) => item?.trim() + ) + const textComments = (commentItem.text_comments || []).filter((item) => + item?.trim() + ) + return checkBoxComments.length + textComments.length + }, []) + + const getCommentContent = useCallback((commentItem: Comment) => { + const mergedComments = [ + ...(commentItem.check_box_comments || []), + ...(commentItem.text_comments || []), + ].filter((item) => item?.trim()) + return mergedComments.length ? mergedComments.join(",") : "无批注" + }, []) + + const getCommentDisplayType = useCallback( + (commentItem: Comment, lastModifiedTimestamp?: number) => { + const type = Math.max(0, Math.min(3, commentItem.comment_type ?? 0)) + if ( + type === 2 && + lastModifiedTimestamp && + lastModifiedTimestamp > commentItem.date && + getCommentCount(commentItem) > 0 + ) { + return 3 + } + return type + }, + [getCommentCount] + ) + const { shift: pressShift } = useKeyEventStore() const continuePolygonTarget = usePaperStore( @@ -696,15 +756,10 @@ const RightObjectTools: React.FC = (props) => { comment.length === 1 ? comment[comment.length - 1] : comment[comment.length - 2] - let type = latest_comment.comment_type - if (type === 2) { - const { last_modified_timestamp } = child[2] - if ( - last_modified_timestamp && - last_modified_timestamp > latest_comment.date - ) - type = 3 - } + const type = getCommentDisplayType( + latest_comment, + child[2].last_modified_timestamp + ) visibleFlag = checkBoxsChecked[3 - type] } if (checkBoxsChecked.every((value) => !value)) @@ -954,12 +1009,7 @@ const RightObjectTools: React.FC = (props) => { 创建: - { - userOpts.find( - (item) => - item.value === child[2]?.uid - )?.label - } + {getUserLabel(child[2]?.uid)} {dayjs( @@ -972,14 +1022,9 @@ const RightObjectTools: React.FC = (props) => { 首次修改: - { - userOpts.find( - (item) => - item.value === - child[2] - ?.first_modified_uid - )?.label - } + {getUserLabel( + child[2]?.first_modified_uid + )} {dayjs( @@ -994,14 +1039,9 @@ const RightObjectTools: React.FC = (props) => { 最新修改: - { - userOpts.find( - (item) => - item.value === - child[2] - ?.last_modified_uid - )?.label - } + {getUserLabel( + child[2]?.last_modified_uid + )} {dayjs( @@ -1027,33 +1067,28 @@ const RightObjectTools: React.FC = (props) => { {comment ? ( - {comment.map((c: any) => { - const count = - c.check_box_comments.length + - c.text_comments.length - const { last_modified_timestamp } = - child[2] - let flag = false - if ( - count > 0 && - last_modified_timestamp && - last_modified_timestamp > c.date - ) - flag = true - - let badgeColor = "gray" - if (c.comment_type === 1) - badgeColor = "green" - if (c.comment_type === 2) - badgeColor = "red" - if (flag) badgeColor = "yellow" + {comment.map((c: Comment) => { + const count = getCommentCount(c) + const commentType = + getCommentDisplayType( + c, + child[2]?.last_modified_timestamp + ) + const badgeColor = + getCheckBoxColor(commentType) + const commentTextColor = + getCommentTextColor(commentType) return ( - - + withArrow + shadow="md" + openDelay={100} + closeDelay={100} + withinPortal> + = (props) => { }}> {count} - - - - {`P${child[2].image_id}:${ - child[2].uid - }:${c.check_box_comments.join( - "," - )},${c.text_comments.join( - "," - )} ${ + + + + {`P${child[2].image_id}:${getUserLabel( + c.uid + )}:${getCommentContent(c)} ${ c.date ? dayjs( c.date * 1000 @@ -1082,8 +1115,8 @@ const RightObjectTools: React.FC = (props) => { : "" }`} - - + + ) })} diff --git a/components/label/components/TopTools.tsx b/components/label/components/TopTools.tsx index 863a0e6..a3f4ae9 100644 --- a/components/label/components/TopTools.tsx +++ b/components/label/components/TopTools.tsx @@ -184,6 +184,9 @@ const TopTools = ( const [operationPickerOpened, setOperationPickerOpened] = useState(false) const [operationKeyword, setOperationKeyword] = useState("") const labelData = useLabelStore((state) => state.label) + const labelDefaultComments = useLabelStore( + (state) => state.labelDefaultComments + ) const setLabel = useLabelStore((state) => state.setLabel) const pushStateStack = useLabelStore((state) => state.pushStateStack) const setLabelTime = useLabelTimeStore((state) => state.setLabelTime) @@ -1035,10 +1038,41 @@ const TopTools = ( }) return } - const finalData = adjustAllPoints( + const recoveredData = adjustAllPoints( backupData, usePaperStore.getState().rasterScale ) + const finalData = safeClone(recoveredData) + for (const [imageId, categoryMap] of finalData.entries()) { + const currentDetailById = new Map() + labelData.get(imageId)?.forEach((objects) => { + objects.forEach(([id, _points, detail]) => { + currentDetailById.set(id, detail) + }) + }) + for (const [operationId, objects] of categoryMap.entries()) { + categoryMap.set( + operationId, + objects.map(([id, points, detail, hollowPoints]) => { + const currentDetail = currentDetailById.get(id) + return [ + id, + points, + { + ...detail, + comment: currentDetail?.comment + ? safeClone(currentDetail.comment) + : safeClone(labelDefaultComments), + last_modified_timestamp: + currentDetail?.last_modified_timestamp ?? + detail.last_modified_timestamp, + }, + hollowPoints, + ] + }) as any + ) + } + } for (const entry of finalData.entries()) { // 赋值用过的id for (const category of entry[1].values()) { @@ -1099,6 +1133,8 @@ const TopTools = ( }, [ activeImage, + labelData, + labelDefaultComments, projectDetail?.label_type, pushStateStack, renderPolygons,