heart
All checks were successful
Deploy to Server / deploy (push) Successful in 38s

This commit is contained in:
jeremygan2021
2026-03-02 20:28:16 +08:00
parent e306ac6f61
commit 2ef1771be0
10 changed files with 198 additions and 7 deletions

View File

@@ -51,9 +51,11 @@ export const uploadUserAvatar = (data) => {
// Community / Forum API
export const getTopics = (params) => api.get('/community/topics/', { params });
export const getTopicDetail = (id) => api.get(`/community/topics/${id}/`);
export const likeTopic = (id) => api.post(`/community/topics/${id}/like/`);
export const createTopic = (data) => api.post('/community/topics/', data);
export const updateTopic = (id, data) => api.patch(`/community/topics/${id}/`, data);
export const getReplies = (params) => api.get('/community/replies/', { params });
export const likeReply = (id) => api.post(`/community/replies/${id}/like/`);
export const createReply = (data) => api.post('/community/replies/', data);
export const uploadMedia = (data) => {
return api.post('/community/media/', data, {

View File

@@ -1,8 +1,8 @@
import React, { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { Typography, Card, Avatar, Tag, Space, Button, Divider, Input, message, Upload, Tooltip, Grid, Modal } from 'antd';
import { UserOutlined, ClockCircleOutlined, EyeOutlined, CheckCircleFilled, LeftOutlined, UploadOutlined, EditOutlined, StarFilled, CloseOutlined } from '@ant-design/icons';
import { getTopicDetail, createReply, uploadMedia, getStarUsers } from '../api';
import { UserOutlined, ClockCircleOutlined, EyeOutlined, CheckCircleFilled, LeftOutlined, UploadOutlined, EditOutlined, StarFilled, CloseOutlined, LikeOutlined, LikeFilled } from '@ant-design/icons';
import { getTopicDetail, createReply, uploadMedia, getStarUsers, likeTopic, likeReply } from '../api';
import { useAuth } from '../context/AuthContext';
import LoginModal from '../components/LoginModal';
import CreateTopicModal from '../components/CreateTopicModal';
@@ -94,6 +94,44 @@ const ForumDetail = () => {
}
};
const handleLikeTopic = async () => {
if (!user) {
setLoginModalVisible(true);
return;
}
try {
const res = await likeTopic(topic.id);
setTopic(prev => ({
...prev,
is_liked: res.data.liked,
like_count: res.data.count
}));
} catch (error) {
message.error('操作失败');
}
};
const handleLikeReply = async (replyId) => {
if (!user) {
setLoginModalVisible(true);
return;
}
try {
const res = await likeReply(replyId);
setTopic(prev => ({
...prev,
replies: prev.replies.map(r => {
if (r.id === replyId) {
return { ...r, is_liked: res.data.liked, like_count: res.data.count };
}
return r;
})
}));
} catch (error) {
message.error('操作失败');
}
};
const handleSubmitReply = async () => {
if (!user) {
setLoginModalVisible(true);
@@ -255,6 +293,10 @@ const ForumDetail = () => {
<EyeOutlined />
<span style={{ fontSize: isMobile ? 12 : 14 }}>{topic.view_count} 阅读</span>
</Space>
<Space style={{ cursor: 'pointer' }} onClick={handleLikeTopic}>
{topic.is_liked ? <LikeFilled style={{ color: '#00b96b' }} /> : <LikeOutlined />}
<span style={{ fontSize: isMobile ? 12 : 14, color: topic.is_liked ? '#00b96b' : 'inherit' }}>{topic.like_count || 0} 点赞</span>
</Space>
</Space>
</div>
@@ -318,6 +360,12 @@ const ForumDetail = () => {
<Text style={{ color: '#aaa', fontWeight: 'bold', fontSize: isMobile ? 13 : 14 }}>{reply.author_info?.nickname}</Text>
{reply.is_pinned && <Tag color="red" style={{ margin: 0 }}>置顶</Tag>}
<Text style={{ color: '#666', fontSize: 12 }}>{new Date(reply.created_at).toLocaleString()}</Text>
</Space>
<Space size={isMobile ? 'small' : 'middle'} align="center">
<Space onClick={() => handleLikeReply(reply.id)} style={{ cursor: 'pointer' }}>
{reply.is_liked ? <LikeFilled style={{ color: '#00b96b' }} /> : <LikeOutlined style={{ color: '#666' }} />}
<span style={{ fontSize: 12, color: reply.is_liked ? '#00b96b' : '#666' }}>{reply.like_count || 0}</span>
</Space>
<Button
type="link"
size="small"
@@ -326,8 +374,8 @@ const ForumDetail = () => {
>
回复
</Button>
<Text style={{ color: '#444', fontSize: 12 }}>#{index + 1}</Text>
</Space>
<Text style={{ color: '#444', fontSize: 12 }}>#{index + 1}</Text>
</div>
<div style={{ color: '#eee', fontSize: isMobile ? 14 : 16 }} className={styles['markdown-body']}>
<ReactMarkdown

View File

@@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react';
import { Typography, Input, Button, List, Tag, Avatar, Card, Space, Spin, message, Badge, Tooltip, Tabs, Row, Col, Grid, Carousel, Modal } from 'antd';
import { SearchOutlined, PlusOutlined, UserOutlined, MessageOutlined, EyeOutlined, CheckCircleFilled, FireOutlined, StarFilled, QuestionCircleOutlined, ShareAltOutlined, SoundOutlined, RightOutlined, CloseOutlined } from '@ant-design/icons';
import { SearchOutlined, PlusOutlined, UserOutlined, MessageOutlined, EyeOutlined, CheckCircleFilled, FireOutlined, StarFilled, QuestionCircleOutlined, ShareAltOutlined, SoundOutlined, RightOutlined, CloseOutlined, LikeOutlined } from '@ant-design/icons';
import { useNavigate } from 'react-router-dom';
import { motion } from 'framer-motion';
import { getTopics, getStarUsers, getAnnouncements } from '../api';
@@ -296,6 +296,10 @@ const ForumList = () => {
<EyeOutlined style={{ fontSize: isMobile ? 14 : 16, color: '#666' }} />
<div style={{ color: '#888', fontSize: isMobile ? 10 : 12 }}>{item.view_count || 0}</div>
</div>
<div style={{ textAlign: 'center', marginTop: isMobile ? 2 : 5 }}>
<LikeOutlined style={{ fontSize: isMobile ? 14 : 16, color: '#666' }} />
<div style={{ color: '#888', fontSize: isMobile ? 10 : 12 }}>{item.like_count || 0}</div>
</div>
</div>
</div>
</Card>