Skip to content

Commit

Permalink
✨ feat(新增回复和评论):
Browse files Browse the repository at this point in the history
  • Loading branch information
MaggieMii committed Aug 4, 2024
1 parent 1ca9bed commit 4d55225
Show file tree
Hide file tree
Showing 14 changed files with 481 additions and 36 deletions.
4 changes: 3 additions & 1 deletion src/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
export default defineAppConfig({
pages: [
'pages/main/index',
'pages/classInfo/index',
'pages/evaluateInfo/index',
'pages/login/index',
'pages/personalPage/index',
'pages/myCollection/index',
'pages/evaluateCourseHistory/index',
'pages/messageNotification/index',
'pages/officialNotification/index',
'pages/feedback/index',
'pages/classInfo/index',
'pages/evaluate/evaluate',
'pages/myclass/myclass',
'pages/research/research',
Expand Down
37 changes: 37 additions & 0 deletions src/assets/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// types.ts
export interface Comment {
id: number;
commentator_id: number;
biz: string;
biz_id: number;
content: string;
root_comment_id: number;
parent_comment_id: number;
reply_to_uid: number;
utime: number;
ctime: number;
user?: User; // 存储用户信息
replies?: Comment[]; // 存储二级评论
}

// 定义评论详情的类型
export type CommentInfoType = {
nickname:string;
avatar:string;
id: number;
content : string;
class_name: string;
teacher: string;
star_rating: number;
total_support_count: number;
total_oppose_count: number;
total_comment_count: number;
utime: number;
ctime: number;
};

export interface User {
id: number;
avatar: string;
nickname: string;
}
12 changes: 12 additions & 0 deletions src/assets/userService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// userService.ts
import { User } from './types';
import { get } from '@/fetch'; // 确保这个路径正确

export const getUserInfo = (userId: number): Promise<User> => {
return get(`/users/${userId}/profile`).then((res) => {
if (res.code === 0 && res.data) {
return res.data;
}
throw new Error('User not found');
});
};
136 changes: 136 additions & 0 deletions src/components/CommentComponent/CommentComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Comment.tsx
import React, { useState, useEffect } from 'react';
import { View, Text,Image } from '@tarojs/components';
import { Comment } from '../../assets/types';
import './index.scss'
import { getUserInfo } from '../../assets/userService';
import { get } from '@/fetch';

interface CommentProps {
comments: Comment[];
onCommentClick: (comment: Comment) => void;
}

const CommentComponent: React.FC<CommentProps> = ({ comments, onCommentClick }) => {
// console.log(comments);
const [allComments, setAllComments] = useState<Comment[]>(comments);

useEffect(() => {
const fetchAllReplies = async () => {
const topLevelComments = allComments.filter(c => c.parent_comment_id === 0 && c.root_comment_id === 0);

const promises = topLevelComments.map(async (comment) => {
const res = await get(`/comments/replies/list?root_id=${comment.id}&cur_comment_id=0&limit=10`);
if (res.code === 0 && Array.isArray(res.data)) {
const replies = res.data.map((reply) => ({
...reply
}));
return { ...comment, replies };
}
return { ...comment, replies: [] };
});

const updatedComments = (await Promise.all(promises));

const commentsWithUserInfo = await Promise.all(
updatedComments.map(async (comment) => {
const user = await getUserInfo(comment.commentator_id);
return { ...comment, user };
})
);

const commentsWithRepliesAndUserInfo = await Promise.all(
commentsWithUserInfo.map(async (comment) => {
const replies = comment.replies || [];
const repliesWithUserInfo = await Promise.all(
replies.map(async (reply) => {
const user = await getUserInfo(reply.commentator_id);
return { ...reply, user };
})
);
return { ...comment, replies: repliesWithUserInfo };
})
);

console.log(commentsWithRepliesAndUserInfo)

setAllComments(commentsWithRepliesAndUserInfo);
};

fetchAllReplies();
}, []);

const ctimeToString = (ctime: number)=>{
const ctimeDate = new Date(ctime);
return <Text className='time'>{ctimeDate.toLocaleString()}</Text>
}

// 辅助函数:获取回复者的昵称
const getReplyToNickname = (replyToUid: number): string => {
// 遍历所有评论的回复
for (const comment of allComments) {
const reply = comment.replies?.find(r => r.commentator_id === replyToUid);
if (reply && reply.user) {
return reply.user.nickname;
}
}
return '未知用户'; // 如果没有找到回复者,返回默认昵称
};

return (
<View className="comments">
{allComments.map((comment) => (
<View key={comment.id} className="acomment" onClick={(e) => {
onCommentClick(comment)
e.stopPropagation();
}
}>
<View className="comment-header">
<Image
src={comment.user?.avatar ?? ''}
className="avatar"
/>
<Text className="nickname">{comment.user?.nickname}</Text>
{
ctimeToString(comment.ctime)
}
</View>
<View className="comment-content">
<Text>{comment.content}</Text>
</View>
<View className="replies">
{comment.replies?.map((reply) => (
<View key={reply.id} className="reply" onClick={(e) => {
onCommentClick(reply);
e.stopPropagation();}
}>
<View className="reply-header">
<Image
src={reply.user?.avatar ?? ''}
className="avatar"
/>
<Text className="nickname">
{reply.user?.nickname}
{reply.root_comment_id !== reply.parent_comment_id ? (
<Text className="reply-indicator">
回复 {getReplyToNickname(reply.reply_to_uid)}
</Text>
) : null}
</Text>
{
ctimeToString(reply.ctime)
}
</View>
<View className="reply-content">
<Text>{reply.content}</Text>
</View>
</View>
))}
</View>
</View>
))}
</View>
);
};

export default CommentComponent;
80 changes: 80 additions & 0 deletions src/components/CommentComponent/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// style.scss
.comments {
padding: 10px;
}

.acomment {
width: 659rpx;
margin: 30rpx 0;
background: #F9F9F2;
border-radius: 43rpx 43rpx 43rpx 43rpx;
border: 2rpx solid #F9F9F2;
padding: 30rpx;
}

.comment-header {
display: flex;
align-items: center;
margin-bottom: 20rpx;
}

.avatar {
width: 57.97rpx;
height: 57.97rpx;
border-radius: 100%;
margin-right: 10px;
border: #d2d5d8 solid 5rpx;
}

.nickname {
font-weight: bold;
font-size: 22rpx;
color: #565552;
}

.comment-content {
margin-top: 5px;
font-weight: 400;
font-size: 22rpx;
color: #565552;
}

.replies {
margin-top: 20px;
padding-left: 10px;
}

.reply .nickname {
font-weight: 400;
font-size: 22rpx;
color: #565552;
}

.reply {
padding-left: 10px;
margin-bottom: 5px;
}

.reply-header {
display: flex;
align-items: center;
}

.reply-content {
margin-top: 5px;
font-weight: 400;
font-size: 22rpx;
color: #565552;
margin-left: 70rpx;
}

.time{
font-weight: 400;
font-size: 18rpx;
color: #A6A193;
margin-left:30rpx;
}

.reply-indicator{
margin-left: 10rpx;
}
4 changes: 4 additions & 0 deletions src/components/comment/comment.scss
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
padding-right: 25rpx;
}

.comment{
position: relative;
}

.comment .tx {
width: 92.39rpx;
height: 92.39rpx;
Expand Down
11 changes: 5 additions & 6 deletions src/components/comment/comment.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import React, { useEffect } from "react";
// import React, { useEffect } from "react";
import { Text, View, Image, Navigator } from "@tarojs/components";
import "./comment.scss";
import ShowStar from "../showStar/showStar";

export default function comment(props) {


// let className = "课程名";
// let teacherName = "老师名";

// 创建一个新的Date对象,传入时间戳
const ctimeDate = new Date(props.ctime);
const utimeDate = new Date(props.utime);
// const utimeDate = new Date(props.utime);


return (
<View className="bigcomment">
<View className="bigcomment" onClick={props.onClick}>
<View className="commentplus">
<View className="classTitle">
{props.class_name + " (" + props.teacher +") " }
Expand Down Expand Up @@ -58,7 +57,7 @@ export default function comment(props) {
<View className="icon">
<Navigator className="iconfont">&#xe785;</Navigator>
</View>
<Text className="text1">{props.dislike}</Text>
<Text className="text1">{props.total_oppose_count}</Text>
</View>
</View>
);
Expand Down
11 changes: 7 additions & 4 deletions src/components/label1/label1.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { Text, View } from '@tarojs/components';
import { useCallback } from 'react';

import './label1.scss';

export default function Label1(props) {

const handleClick = () => props.onClick(props.content);
const handleClick = useCallback((event) => {
event.stopPropagation(); // 阻止事件冒泡
props.onClick(props.content);
}, [props.content, props.onClick]);

return (
<View className="label1" onClick={handleClick}>
<View className="label1" onClick={handleClick}>
<Text className="labeltext">{props.content}</Text>
</View>
);
}
}
27 changes: 18 additions & 9 deletions src/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,28 @@ export async function post(url = '', data = {}, isToken = true) {
'Content-Type': 'application/json;charset=utf-8',
};

if (isToken) {
Taro.getStorage({
key: 'token',
success: (res) => {
const token = res.data;
if (token) header['Authorization'] = token;
else {
Taro.navigateTo({ url: '/pages/login/index' });
const getToken = () => {
return new Promise((resolve, reject) => {
Taro.getStorage({
key: "token",
success: (res) => {
const token = res.data;
if (token) {
resolve(token); // 如果token存在,解析Promise
} else {
reject(new Error("No token found")); // 如果没有token,拒绝Promise
Taro.navigateTo({ url: "/pages/login/index" }); // 导航到登录页面
}
},
fail: (err) => {
reject(new Error(`Failed to get token: ${err}`)); // 存储操作失败时拒绝Promise
}
},
});
});
}

if (isToken) header["Authorization"] = `Bearer ${await getToken()}`;

try {
const response = await Taro.request({
url: `${preUrl}${url}`,
Expand Down
3 changes: 3 additions & 0 deletions src/pages/evaluateInfo/index.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default definePageConfig({
navigationBarTitleText: '首页',
});
Loading

0 comments on commit 4d55225

Please sign in to comment.