blob: 05c516531699d52931e65adc366f193419c8eafa [file] [log] [blame]
import React, { useState, useEffect, useCallback } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { Button, Card, Form, Input, List, message, Avatar, Spin, Empty } from 'antd';
import { ArrowLeftOutlined, UserOutlined } from '@ant-design/icons';
import { Layout } from 'antd';
import { listComments, addComment } from './service';
import { responseSysTorrentComment, SysTorrentComment } from './data';
const { Content } = Layout;
const { TextArea } = Input;
interface CommentItem {
id: number;
name: string;
content: string;
createTime: string;
createBy: string;
torrentId: number;
}
const TorrentComments: React.FC = () => {
const { torrentId } = useParams<{ torrentId: string }>();
const navigate = useNavigate();
const [form] = Form.useForm();
const [comments, setComments] = useState<CommentItem[]>([]);
const [submitting, setSubmitting] = useState(false);
const [loading, setLoading] = useState(false);
// 格式化时间
const formatTime = (time: string | Date | null | undefined): string => {
if (!time) return '未知时间';
try {
const date = new Date(time);
const now = new Date();
const diff = now.getTime() - date.getTime();
// 小于1分钟
if (diff < 60 * 1000) {
return '刚刚';
}
// 小于1小时
if (diff < 60 * 60 * 1000) {
return `${Math.floor(diff / (60 * 1000))}分钟前`;
}
// 小于24小时
if (diff < 24 * 60 * 60 * 1000) {
return `${Math.floor(diff / (60 * 60 * 1000))}小时前`;
}
// 小于7天
if (diff < 7 * 24 * 60 * 60 * 1000) {
return `${Math.floor(diff / (24 * 60 * 60 * 1000))}天前`;
}
// 否则显示具体日期
return date.toLocaleDateString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
});
} catch (error) {
return '未知时间';
}
};
// 获取用户显示名称
const getUserDisplayName = (userId: number | null | undefined): string => {
if (!userId) return '匿名用户';
return `用户${userId}`;
};
// 获取用户头像字符
const getAvatarChar = (userName: string): string => {
if (!userName || userName === '匿名用户') return '?';
// 如果是"用户123"格式,取数字的最后一位
const match = userName.match(/\d+$/);
if (match) {
return match[0].slice(-1);
}
return userName[0].toUpperCase();
};
// 获取评论列表
const fetchComments = useCallback(async () => {
if (!torrentId) return;
setLoading(true);
try {
const res = await listComments(Number(torrentId));
console.log('获取评论列表:', res);
if (res) {
const formattedComments: SysTorrentComment[] = res.data.map((comment: SysTorrentComment) => ({
id: comment.commentId ?? 0,
name: comment.userName ?? '匿名用户',
content: comment.content ?? '无内容',
createTime: comment.createTime || '',
createBy: getUserDisplayName(comment.userId),
torrentId: comment.torrentId ?? 0,
}));
// 按时间倒序排列,最新的在前面
formattedComments.sort((a, b) => {
const timeA = a.createTime ? new Date(a.createTime).getTime() : 0;
const timeB = b.createTime ? new Date(b.createTime).getTime() : 0;
return timeB - timeA;
});
setComments(formattedComments);
} else {
message.error(res?.msg || '获取评论列表失败');
setComments([]);
}
} catch (error) {
console.error('获取评论失败:', error);
message.error('获取评论失败,请稍后重试');
setComments([]);
} finally {
setLoading(false);
}
}, [torrentId]);
useEffect(() => {
if (torrentId) {
fetchComments();
}
}, [torrentId, fetchComments]);
// 提交评论
const handleSubmit = async () => {
try {
const values = await form.validateFields();
setSubmitting(true);
// 调用添加评论的API
const response = await addComment({
torrentId: Number(torrentId),
content: values.content.trim(),
});
if (response?.code === 200) {
message.success('评论成功');
form.resetFields();
// 刷新评论列表
await fetchComments();
} else {
message.error(response?.msg || '评论失败,请稍后重试');
}
} catch (error) {
console.error('评论失败:', error);
message.error('评论失败,请稍后重试');
} finally {
setSubmitting(false);
}
};
// 处理按下 Ctrl+Enter 提交
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.ctrlKey && e.key === 'Enter' && !submitting) {
handleSubmit();
}
};
return (
<Content style={{
height: '100vh',
display: 'flex',
flexDirection: 'column',
overflow: 'hidden',
backgroundColor: '#f5f5f5'
}}>
{/* 顶部标题栏 */}
<div style={{
padding: '16px',
borderBottom: '1px solid #f0f0f0',
display: 'flex',
alignItems: 'center',
backgroundColor: '#fff',
zIndex: 10,
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.06)'
}}>
<Button
type="link"
icon={<ArrowLeftOutlined />}
onClick={() => navigate(-1)}
style={{ marginRight: '10px', padding: 0 }}
/>
<span style={{ fontSize: '16px', fontWeight: 'bold' }}>
种子评论 {comments.length > 0 && `(${comments.length})`}
</span>
</div>
{/* 评论列表区域 - 可滚动 */}
<div style={{
flex: 1,
overflowY: 'auto',
padding: '16px',
paddingBottom: '8px'
}}>
<Spin spinning={loading}>
{comments.length === 0 && !loading ? (
<Empty
description="暂无评论"
style={{ marginTop: '60px' }}
/>
) : (
<List
className="comment-list"
itemLayout="horizontal"
dataSource={comments}
renderItem={(item) => (
<Card
style={{
marginBottom: '12px',
borderRadius: '8px',
boxShadow: '0 1px 2px rgba(0, 0, 0, 0.03)'
}}
bodyStyle={{ padding: '12px 16px' }}
>
<List.Item style={{ border: 'none', padding: 0 }}>
<List.Item.Meta
avatar={
<Avatar
style={{
backgroundColor: '#1890ff',
verticalAlign: 'middle'
}}
size="default"
icon={<UserOutlined />}
>
{getAvatarChar(item.createBy)}
</Avatar>
}
title={
<div style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center'
}}>
<span style={{ fontWeight: 500 }}>{item.createBy}</span>
<span style={{
color: '#8c8c8c',
fontSize: '12px',
fontWeight: 'normal'
}}>
{formatTime(item.createTime)}
</span>
</div>
}
description={
<div style={{
marginTop: '8px',
color: '#262626',
fontSize: '14px',
lineHeight: '22px',
wordBreak: 'break-word'
}}>
{item.content}
</div>
}
/>
</List.Item>
</Card>
)}
/>
)}
</Spin>
</div>
{/* 评论输入框 - 固定在底部 */}
<div style={{
padding: '16px',
backgroundColor: '#fff',
borderTop: '1px solid #f0f0f0',
boxShadow: '0 -2px 8px rgba(0, 0, 0, 0.06)'
}}>
<Form form={form} onFinish={handleSubmit}>
<Form.Item
name="content"
rules={[
{ required: true, message: '请输入评论内容' },
{ whitespace: true, message: '评论内容不能为空' },
{ max: 500, message: '评论内容不能超过500个字符' }
]}
style={{ marginBottom: '12px' }}
>
<TextArea
rows={3}
placeholder="请输入您的评论(Ctrl+Enter 快速提交)"
maxLength={500}
showCount
onKeyDown={handleKeyDown}
disabled={submitting}
/>
</Form.Item>
<Form.Item style={{ marginBottom: 0, textAlign: 'right' }}>
<Button
htmlType="submit"
loading={submitting}
type="primary"
disabled={loading}
>
提交评论
</Button>
</Form.Item>
</Form>
</div>
</Content>
);
};
export default TorrentComments;