blob: a40fb689c72784b9dea14d2e81d8afa599b768d6 [file] [log] [blame]
San3yuana2ee30b2025-06-05 21:20:17 +08001import React, { useEffect, useState } from 'react';
2import { useParams } from 'react-router-dom';
3import styles from './PostDetail.module.css';
4import { Card, List, Typography, Button, Input, Spin, Empty } from 'antd';
5type CommentProps = {
6 children?: React.ReactNode;
7};
8import { getPostDetail } from '@/api/post';
9import { getPostComments } from '@/api/comment';
10import { useSearchParams } from 'react-router-dom';
11import request from '@/utils/request';
12import { useApi } from '@/hooks/request';
13import Navbar from '@/components/navbar/navbar';
14
15const { Title, Text, Paragraph } = Typography;
16const { TextArea } = Input;
17
18export interface PostResponse {
19 createdAt?: number;
20 hotScore?: number;
21 lastCalculated?: number;
22 postContent?: string;
23 postId?: number;
24 postTitle?: string;
25 postType?: string;
26 userId?: number;
27 viewCount?: number;
28 [property: string]: any;
29}
30
31export interface CommentResponse {
32 commentId?: number;
33 content?: string;
34 createdAt?: number;
35 parentCommentId?: number | null;
36 postId?: number;
37 replies?: CommentResponse[];
38 userId?: number;
39 [property: string]: any;
40}
41
42const PostDetail: React.FC = () => {
43 const [searchParams] = useSearchParams();
44 const postId = searchParams.get('postId');
45 const { refresh: getPostDetailRefresh } = useApi(() => request.get(getPostDetail + `/${postId}`), false);
46 const { refresh: getPostCommentsRefresh } = useApi(() => request.get(getPostComments + `/${postId}`), false);
47 const [post, setPost] = useState<PostResponse | null>(null);
48 const [comments, setComments] = useState<CommentResponse[]>([]);
49 const [newComment, setNewComment] = useState<string>('');
50 const [loading, setLoading] = useState<boolean>(true);
51
52 useEffect(() => {
53 console.log('postId', postId);
54 if (!postId) return;
55 const fetchData = async () => {
56 setLoading(true);
57 const res = await getPostDetailRefresh();
58 if (res == null || (res as any).error) {
59 setLoading(false);
60 return;
61 }
62 setPost(res as PostResponse);
63 await getPostCommentsRefresh();
64 setComments(res as CommentResponse[]);
65 setLoading(false);
66 };
67 fetchData();
68 }, [postId]);
69
70 if (loading) return <div className={styles.center}><Spin /></div>;
71 if (!post) return <div className={styles.center}><Empty description="未找到帖子" /></div>;
72
73 return (
74 <div className={styles.container}>
75 <div className={styles.nav}>
76 <Navbar current={post.postType} />
77 </div>
78 <div className={styles.content}>
79 <div className={styles.postDetail}>
80
81 </div >
82 <Card title={post.postTitle} className={styles.card}>
83 <Paragraph>{post.postContent}</Paragraph>
84 <div className={styles.actions}>
85 <Button type="primary" onClick={() => setNewComment('')}>评论</Button>
86 </div>
87 </Card>
88
89 <List
90 className={styles.commentList}
91 header={<Title level={4}>评论区</Title>}
92 dataSource={comments}
93 renderItem={(item) => (
94 <List.Item key={item.commentId}>
95 <List.Item.Meta
96 title={<Text strong>{item.userId}</Text>}
97 description={<Text>{item.content}</Text>}
98 />
99 </List.Item>
100 )}
101 />
102
103 <TextArea
104 rows={4}
105 value={newComment}
106 onChange={(e) => setNewComment(e.target.value)}
107 placeholder="写下你的评论..."
108 />
109 </div>
110 </div>
111 );
112};
113
114export default PostDetail;