gongxiangp2/components/work-review/WorkReviewAnnotationMarker.tsx
2026-08-01 16:16:20 +08:00

71 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client'
import type { WorkReviewImageAnnotation, WorkReviewRole } from '@/types/work-review'
export type WorkReviewDisplayAnnotation = {
annotation: WorkReviewImageAnnotation
markerNumber: number
reviewerName?: string
reviewerRole?: WorkReviewRole
draft?: boolean
positionEditable?: boolean
}
function markerTone(item: WorkReviewDisplayAnnotation) {
if (item.draft) return 'bg-[#8a5200] text-white ring-[#fff3d6]'
if (item.reviewerRole === 'final_reviewer') return 'bg-[#087a3c] text-white ring-[#d9f6e5]'
return 'bg-[#0050cb] text-white ring-[#dcecff]'
}
export function WorkReviewAnnotationMarker({
item,
onClick,
showComment = true,
}: {
item: WorkReviewDisplayAnnotation
onClick?: () => void
showComment?: boolean
}) {
const { annotation } = item
const alignRight = annotation.x > 0.62
const roleLabel = item.draft
? '当前批注'
: item.reviewerRole === 'final_reviewer'
? '元泽'
: '评审人'
const summary = annotation.comment.trim() || '待填写修改意见'
const positionState = item.positionEditable ? ',位置可调整' : ''
const label = `${roleLabel}标注 ${item.markerNumber}${positionState}${item.reviewerName ? `,${item.reviewerName}` : ''}:${summary}`
const visualTitle = showComment ? label : `${roleLabel}标注 ${item.markerNumber}`
return (
<button
type="button"
onClick={(event) => {
event.stopPropagation()
onClick?.()
}}
onPointerDown={(event) => event.stopPropagation()}
onPointerUp={(event) => event.stopPropagation()}
aria-label={label}
title={visualTitle}
className={`group absolute z-20 h-11 w-11 -translate-x-1/2 -translate-y-1/2 outline-none ${item.positionEditable ? 'cursor-move' : 'cursor-pointer'}`}
style={{ left: `${annotation.x * 100}%`, top: `${annotation.y * 100}%` }}
>
<span className={`absolute left-1/2 top-1/2 flex h-7 w-7 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full text-[11px] font-black shadow-[0_3px_10px_rgba(15,23,42,0.35)] ring-4 ${markerTone(item)} ${item.positionEditable ? 'outline outline-2 outline-offset-2 outline-[#8a5200]' : ''} group-focus-visible:ring-[#8ab9ff]`}>
{item.markerNumber}
</span>
<span
className={`pointer-events-none absolute top-1/2 max-w-[140px] -translate-y-1/2 truncate rounded-full bg-[#101828]/90 px-3 py-1.5 text-[11px] font-semibold text-white shadow-[0_4px_14px_rgba(15,23,42,0.24)] sm:max-w-[220px] ${
showComment ? 'block' : 'hidden'
} ${
alignRight ? 'right-9' : 'left-9'
}`}
aria-hidden={!showComment}
>
{summary}
</span>
</button>
)
}