'use client'; import { useEffect, useMemo, useState } from 'react'; import { MessageSquare, Send, Trash2 } from 'lucide-react'; import { useAuthStore } from '@/stores/useAuthStore'; import { useCommentStore, commentKey } from '@/stores/useCommentStore'; import { useMemberStore } from '@/stores/useMemberStore'; import { extractMentionNames, mergeMentionMemberIds } from '@/lib/comment-mentions'; import { formatDateTime } from '@/lib/format'; export type CommentEntityType = 'dev_task' | 'test_case' | 'bug' | 'requirement' | 'version_plan'; interface Props { entityType: CommentEntityType; entityId: string; entityVersionId?: string | null; productId?: string | null; projectId?: string | null; versionId?: string | null; readOnly?: boolean; } export function CommentPanel({ entityType, entityId, entityVersionId, productId, projectId, versionId, readOnly = false }: Props) { const user = useAuthStore((s) => s.user); const { members, fetchMembers } = useMemberStore(); const { commentsByKey, fetchComments, createComment, deleteComment } = useCommentStore(); const [content, setContent] = useState(''); const [selectedIds, setSelectedIds] = useState([]); const key = commentKey(entityType, entityId); const comments = commentsByKey[key] ?? []; useEffect(() => { void fetchComments(entityType, entityId).catch(() => {}); void fetchMembers().catch(() => {}); }, [entityId, entityType, fetchComments, fetchMembers]); const mentionNames = useMemo(() => extractMentionNames(content), [content]); const mentionMemberIds = useMemo(() => mergeMentionMemberIds({ content, explicitMemberIds: selectedIds, members: members.map((member) => ({ id: member.id, name: member.name })), }), [content, members, selectedIds]); const submit = async () => { if (readOnly || !user?.id || !content.trim()) return; await createComment({ actorId: user.id, entityType, entityId, entityVersionId, productId, projectId, versionId, content: content.trim(), mentionMemberIds, }); setContent(''); setSelectedIds([]); }; const toggleMember = (id: string) => { setSelectedIds((current) => current.includes(id) ? current.filter((item) => item !== id) : [...current, id]); }; return (
评论
{comments.length === 0 ? (

暂无评论

) : ( comments.map((comment) => { const author = members.find((member) => member.id === comment.authorId)?.name ?? comment.authorId; return (
{author} {formatDateTime(comment.createdAt)} {!readOnly && user?.id === comment.authorId && ( )}

{comment.content}

); }) )}
{!readOnly && (