- @chakra-ui/icons → lucide-react - react-icons → lucide-react - 涉及 49 个组件文件 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
180 lines
4.9 KiB
JavaScript
180 lines
4.9 KiB
JavaScript
// src/components/EventCommentSection/CommentItem.js
|
||
/**
|
||
* 单条评论组件
|
||
* 功能:显示用户头像、昵称、时间、评论内容、删除按钮
|
||
*/
|
||
|
||
import React, { useState } from 'react';
|
||
import {
|
||
Box,
|
||
HStack,
|
||
VStack,
|
||
Avatar,
|
||
Text,
|
||
IconButton,
|
||
useColorModeValue,
|
||
Tooltip,
|
||
AlertDialog,
|
||
AlertDialogBody,
|
||
AlertDialogFooter,
|
||
AlertDialogHeader,
|
||
AlertDialogContent,
|
||
AlertDialogOverlay,
|
||
Button,
|
||
useDisclosure,
|
||
} from '@chakra-ui/react';
|
||
import { Trash2 } from 'lucide-react';
|
||
import dayjs from 'dayjs';
|
||
import 'dayjs/locale/zh-cn';
|
||
|
||
dayjs.locale('zh-cn');
|
||
|
||
const CommentItem = ({ comment, currentUserId, onDelete }) => {
|
||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||
const cancelRef = React.useRef();
|
||
const [isDeleting, setIsDeleting] = useState(false);
|
||
const itemBg = useColorModeValue('gray.50', 'gray.700');
|
||
const usernameColor = useColorModeValue('gray.800', 'gray.100');
|
||
const timeColor = useColorModeValue('gray.500', 'gray.400');
|
||
const contentColor = useColorModeValue('gray.700', 'gray.300');
|
||
|
||
// 判断当前用户是否可以删除此评论
|
||
const canDelete = currentUserId && (
|
||
comment.author?.id === currentUserId ||
|
||
comment.user_id === currentUserId
|
||
);
|
||
|
||
// 处理删除
|
||
const handleDelete = async () => {
|
||
if (!onDelete) return;
|
||
setIsDeleting(true);
|
||
try {
|
||
await onDelete(comment.id);
|
||
onClose();
|
||
} catch (error) {
|
||
// 错误由父组件处理
|
||
} finally {
|
||
setIsDeleting(false);
|
||
}
|
||
};
|
||
|
||
// 格式化时间
|
||
const formatTime = (timestamp) => {
|
||
const now = dayjs();
|
||
const time = dayjs(timestamp);
|
||
const diffMinutes = now.diff(time, 'minutes');
|
||
const diffHours = now.diff(time, 'hours');
|
||
const diffDays = now.diff(time, 'days');
|
||
|
||
if (diffMinutes < 1) {
|
||
return '刚刚';
|
||
} else if (diffMinutes < 60) {
|
||
return `${diffMinutes}分钟前`;
|
||
} else if (diffHours < 24) {
|
||
return `${diffHours}小时前`;
|
||
} else if (diffDays < 7) {
|
||
return `${diffDays}天前`;
|
||
} else {
|
||
return time.format('MM-DD HH:mm');
|
||
}
|
||
};
|
||
|
||
return (
|
||
<>
|
||
<Box
|
||
p={3}
|
||
bg={itemBg}
|
||
borderRadius="md"
|
||
transition="all 0.2s"
|
||
_hover={{
|
||
transform: 'translateY(-2px)',
|
||
boxShadow: 'sm',
|
||
}}
|
||
position="relative"
|
||
>
|
||
<HStack align="start" spacing={3}>
|
||
{/* 用户头像 */}
|
||
<Avatar
|
||
size="sm"
|
||
name={comment.author?.username || 'Anonymous'}
|
||
src={comment.author?.avatar}
|
||
/>
|
||
|
||
{/* 评论内容区 */}
|
||
<VStack align="stretch" flex={1} spacing={1}>
|
||
{/* 用户名和时间 */}
|
||
<HStack spacing={2} justify="space-between">
|
||
<HStack spacing={2}>
|
||
<Text fontSize="sm" fontWeight="bold" color={usernameColor}>
|
||
{comment.author?.username || 'Anonymous'}
|
||
</Text>
|
||
<Text fontSize="xs" color={timeColor}>
|
||
{formatTime(comment.created_at)}
|
||
</Text>
|
||
</HStack>
|
||
|
||
{/* 删除按钮 - 只对自己的评论显示 */}
|
||
{canDelete && (
|
||
<Tooltip label="删除评论" placement="top">
|
||
<IconButton
|
||
icon={<Trash2 size={14} />}
|
||
size="xs"
|
||
variant="ghost"
|
||
colorScheme="red"
|
||
aria-label="删除评论"
|
||
onClick={onOpen}
|
||
opacity={0.6}
|
||
_hover={{ opacity: 1 }}
|
||
/>
|
||
</Tooltip>
|
||
)}
|
||
</HStack>
|
||
|
||
{/* 评论内容 */}
|
||
<Text fontSize="sm" color={contentColor} lineHeight="1.6">
|
||
{comment.content}
|
||
</Text>
|
||
</VStack>
|
||
</HStack>
|
||
</Box>
|
||
|
||
{/* 删除确认对话框 */}
|
||
<AlertDialog
|
||
isOpen={isOpen}
|
||
leastDestructiveRef={cancelRef}
|
||
onClose={onClose}
|
||
isCentered
|
||
>
|
||
<AlertDialogOverlay>
|
||
<AlertDialogContent>
|
||
<AlertDialogHeader fontSize="lg" fontWeight="bold">
|
||
删除评论
|
||
</AlertDialogHeader>
|
||
|
||
<AlertDialogBody>
|
||
确定要删除这条评论吗?此操作不可撤销。
|
||
</AlertDialogBody>
|
||
|
||
<AlertDialogFooter>
|
||
<Button ref={cancelRef} onClick={onClose} isDisabled={isDeleting}>
|
||
取消
|
||
</Button>
|
||
<Button
|
||
colorScheme="red"
|
||
onClick={handleDelete}
|
||
ml={3}
|
||
isLoading={isDeleting}
|
||
loadingText="删除中..."
|
||
>
|
||
删除
|
||
</Button>
|
||
</AlertDialogFooter>
|
||
</AlertDialogContent>
|
||
</AlertDialogOverlay>
|
||
</AlertDialog>
|
||
</>
|
||
);
|
||
};
|
||
|
||
export default CommentItem;
|