diff --git a/.gitignore b/.gitignore index 938ee60..257c2e5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ -back/data -back/__pycache__ \ No newline at end of file +back/data/ +back/__pycache__/ +**/__pycache__/ +**/*.pyc diff --git a/back/data/db.sqlite b/back/data/db.sqlite deleted file mode 100644 index 9d56b1b..0000000 Binary files a/back/data/db.sqlite and /dev/null differ diff --git a/back/data/img/7628fb744dc44727aa8e0b4a0b5fb5d9.jpg b/back/data/img/7628fb744dc44727aa8e0b4a0b5fb5d9.jpg deleted file mode 100644 index 4b1aca3..0000000 Binary files a/back/data/img/7628fb744dc44727aa8e0b4a0b5fb5d9.jpg and /dev/null differ diff --git a/back/data/img/c66118de8ddb4eb587d955088dfeb3a5.png b/back/data/img/c66118de8ddb4eb587d955088dfeb3a5.png deleted file mode 100644 index 357ba9f..0000000 Binary files a/back/data/img/c66118de8ddb4eb587d955088dfeb3a5.png and /dev/null differ diff --git a/back/main.py b/back/main.py index d54ab1e..d94665f 100644 --- a/back/main.py +++ b/back/main.py @@ -340,14 +340,23 @@ def get_comments(): if not submission or submission.status != "Pass": return jsonify({"code": 2002, "data": "投稿不存在"}) + page = request.args.get("page", 1, type=int) + if page < 1: + page = 1 + + per_page = 5 + pagination = Comment.query.filter_by(submission_id=submission_id)\ + .order_by(Comment.id.asc())\ + .paginate(page=page, per_page=per_page, error_out=False) + data = [{ "id": c.id, "nickname": c.nickname, "content": c.content, "parent_comment_id": c.parent_comment_id if c.parent_comment_id is not None else 0 - } for c in submission.comments] + } for c in pagination.items] - return jsonify({"code": 1000, "data": data}) + return jsonify({"code": 1000, "data": {"comments": data, "total_pages": pagination.pages}}) except Exception as e: return jsonify({"code": 2003, "data": str(e)}) @@ -469,8 +478,8 @@ def get_statics(): except Exception as e: return jsonify({"code": 2003, "data": str(e)}) -@app.route('/api/10_info', methods=['GET']) -def get_10_info(): +@app.route('/api/posts_info', methods=['GET']) +def get_posts_info(): try: page = request.args.get("page", 1, type=int) if page < 1: @@ -503,8 +512,8 @@ def get_10_info(): except Exception as e: return jsonify({"code": 2003, "data": str(e)}) -# --- 菜单 --- -@app.route('/get/teapot', methods=['GET']) +# --- 彩蛋 --- +@app.route('/api/teapot', methods=['GET']) def return_418(): abort(418) diff --git a/front/src/api.ts b/front/src/api.ts index 3aacf0a..2f74851 100644 --- a/front/src/api.ts +++ b/front/src/api.ts @@ -175,7 +175,7 @@ export interface Article { export const fetchArticles = async (page: number, signal?: AbortSignal): Promise => { try { - const response = await fetch(`/api/10_info?page=${page}`, { signal }); + const response = await fetch(`/api/posts_info?page=${page}`, { signal }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } @@ -219,15 +219,23 @@ export interface Comment { parent_comment_id: number; } -export const getComments = async (id: string | number): Promise => { +export interface CommentPage { + comments: Comment[]; + total_pages: number; +} + +export const getComments = async (id: string | number, page: number = 1): Promise => { try { - const response = await fetch(`/api/get/comment?id=${id}`); + const response = await fetch(`/api/get/comment?id=${id}&page=${page}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const json = await response.json(); - if (json.code === 1000 && Array.isArray(json.data)) { - return json.data as Comment[]; + if (json.code === 1000 && json.data && Array.isArray(json.data.comments)) { + return { + comments: json.data.comments as Comment[], + total_pages: Number(json.data.total_pages) || 0, + }; } throw new Error('Invalid response code or missing data'); } catch (error) { diff --git a/front/src/components/CommentSection.tsx b/front/src/components/CommentSection.tsx index 30897ec..0a19edd 100644 --- a/front/src/components/CommentSection.tsx +++ b/front/src/components/CommentSection.tsx @@ -12,7 +12,7 @@ import { Toast, ToastTitle, } from '@fluentui/react-components'; -import { Dismiss24Regular, ArrowReply24Regular } from '@fluentui/react-icons'; +import { Dismiss24Regular, ArrowReply24Regular, ArrowClockwise24Regular } from '@fluentui/react-icons'; import { getComments, postComment } from '../api'; import type { Comment as CommentType } from '../api'; import { useLayout } from '../context/LayoutContext'; @@ -91,6 +91,15 @@ const useStyles = makeStyles({ color: tokens.colorBrandForeground1, textDecoration: 'none', }, + loadMore: { + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + gap: tokens.spacingHorizontalXS, + color: tokens.colorBrandForeground1, + cursor: 'pointer', + marginTop: tokens.spacingVerticalS, + }, }); // 自定义 remark 插件,用于高亮 #tag @@ -137,17 +146,29 @@ const CommentSection: React.FC = ({ postId }) => { const [nickname, setNickname] = useState(''); const [replyTo, setReplyTo] = useState(null); const [loading, setLoading] = useState(false); + const [loadingMore, setLoadingMore] = useState(false); + const [page, setPage] = useState(1); + const [totalPages, setTotalPages] = useState(0); const commentCardRefs = useRef>(new Map()); - useEffect(() => { - fetchComments(); +useEffect(() => { + setComments([]); + setPage(1); + setTotalPages(0); + fetchComments(1, false); }, [postId]); - const fetchComments = async () => { + const fetchComments = async (targetPage: number, append: boolean) => { try { - setLoading(true); - const data = await getComments(postId); - setComments(data as CommentType[]); + if (append) { + setLoadingMore(true); + } else { + setLoading(true); + } + const data = await getComments(postId, targetPage); + setComments(prev => (append ? [...prev, ...data.comments] : data.comments)); + setPage(targetPage); + setTotalPages(data.total_pages || 0); } catch (error) { dispatchToast( @@ -157,7 +178,11 @@ const CommentSection: React.FC = ({ postId }) => { ); console.error('Error fetching comments:', error); } finally { - setLoading(false); + if (append) { + setLoadingMore(false); + } else { + setLoading(false); + } } }; @@ -188,7 +213,7 @@ const CommentSection: React.FC = ({ postId }) => { ); setContent(''); if (replyTo) setReplyTo(null); - fetchComments(); + fetchComments(1, false); } catch (error: any) { dispatchToast( @@ -300,6 +325,18 @@ const CommentSection: React.FC = ({ postId }) => { {loading && 加载评论中..} {!loading && comments.length === 0 && 暂无评论} {renderComments()} + {totalPages > 1 && page < totalPages && ( +
{ + if (loading || loadingMore) return; + fetchComments(page + 1, true); + }} + > + + 加载更多 +
+ )} );