Explorar o código

发送评论刷新前

xiang hai 1 semana
pai
achega
891f62053b
Modificáronse 19 ficheiros con 879 adicións e 342 borrados
  1. 21 0
      src/apis/comment.ts
  2. 1 1
      src/pages/layout/components/CreatePlaylistModal/index.tsx
  3. 3 0
      src/pages/layout/components/LoginContent/components/GiteeLogin.tsx
  4. 2 2
      src/pages/layout/pages/SongDetail/index.tsx
  5. 42 21
      src/pages/layout/pages/Video/Video_player/index.tsx
  6. 4 7
      src/pages/layout/pages/Video/index.tsx
  7. 69 0
      src/pages/layout/pages/find/rank/compomemts/CommentInput/index.css
  8. 72 0
      src/pages/layout/pages/find/rank/compomemts/CommentInput/index.less
  9. 90 0
      src/pages/layout/pages/find/rank/compomemts/CommentInput/index.tsx
  10. 22 0
      src/pages/layout/pages/find/rank/compomemts/CommentItem/index.css
  11. 25 0
      src/pages/layout/pages/find/rank/compomemts/CommentItem/index.less
  12. 205 0
      src/pages/layout/pages/find/rank/compomemts/CommentItem/index.tsx
  13. 3 4
      src/pages/layout/pages/find/rank/compomemts/RankPlaylist/index.tsx
  14. 1 67
      src/pages/layout/pages/find/rank/compomemts/Rank_Recommend_body_list_Comment/index.css
  15. 3 65
      src/pages/layout/pages/find/rank/compomemts/Rank_Recommend_body_list_Comment/index.less
  16. 14 61
      src/pages/layout/pages/find/rank/compomemts/Rank_Recommend_body_list_Comment/index.tsx
  17. 48 7
      src/pages/layout/pages/find/rank/compomemts/Rank_Recommend_body_list_Comment_list/indes.css
  18. 88 26
      src/pages/layout/pages/find/rank/compomemts/Rank_Recommend_body_list_Comment_list/indes.less
  19. 166 81
      src/pages/layout/pages/find/rank/compomemts/Rank_Recommend_body_list_Comment_list/index.tsx

+ 21 - 0
src/apis/comment.ts

@@ -0,0 +1,21 @@
+import { request } from "@/utils"
+
+export const getCommentListByIdType = (data) => {
+  return request.post('/comment/getCommentList', data)
+}
+
+export const addCommentByIdType = (data) => {
+  return request.post('/comment/add', data)
+}
+
+export const addLikeCount = (id: number) => {
+  return request.get(`/comment/AddlikeCount`,{params:{id}})
+}
+
+export const cancelLikeCount = (id: number) => {
+  return request.get(`/comment/CancelLikeCount`,{params:{id}})
+}
+
+export const getCommentListByPid = (id: number) => {
+  return request.get(`/comment/listByPid`,{params:{id}})
+}

+ 1 - 1
src/pages/layout/components/CreatePlaylistModal/index.tsx

@@ -134,7 +134,7 @@ const CreatePlaylistModal: React.FC<CreatePlaylistModalProps> = ({
 
   return (
     <>
-      {contextHolder} {/* 使用 contextHolder 替代 messageApi */}
+      {contextHolder}
       <Modal
         title="新建歌单"
         open={open}

+ 3 - 0
src/pages/layout/components/LoginContent/components/GiteeLogin.tsx

@@ -35,6 +35,9 @@ const GiteeLogin: React.FC<GiteeLoginProps> = ({ onSuccess }) => {
     <>
       <div 
         onClick={() => setIsModalOpen(true)}
+        //悬浮变手
+
+        style={{cursor: 'pointer'}}
       >
         Gitee 登录
       </div>

+ 2 - 2
src/pages/layout/pages/SongDetail/index.tsx

@@ -87,8 +87,8 @@ const SongDetail = () => {
   return (
     <div className='SongDetail'>
       <SongDetailPage song={song} />
-      <Rank_Recommend_body_list_Comment />
-      <Rank_Recommend_body_list_Comment_list />
+      <Rank_Recommend_body_list_Comment contentId={song.id} type={0} />
+      <Rank_Recommend_body_list_Comment_list contentId={song.id} type={0} />
     </div>
   )
 }

+ 42 - 21
src/pages/layout/pages/Video/Video_player/index.tsx

@@ -2,23 +2,24 @@ import { useEffect, useRef, useState } from 'react';
 import { useLocation, useParams } from 'react-router-dom';
 import DPlayer from 'dplayer';
 import './index.css';
-import { 
+import {
   getMvById,
   toggleMvFavoriteApi,
-  checkMvFavoriteApi
+  checkMvFavoriteApi,
+  GetFileUrlByMd5Api  // 添加MD5接口导入
 } from '@/apis/Mv';
 import { Button, message } from 'antd';
 import { HeartOutlined, HeartFilled } from '@ant-design/icons';
 
 interface VideoPlayerProps {
-  mvId?: string;
+  mvId?: number;
 }
 
 const Video_Player = ({ mvId }: VideoPlayerProps) => {
   const location = useLocation();
   const params = useParams<{ id: string }>();
   const actualMvId = mvId || params.id;
-  
+
   const dpContainer = useRef<HTMLDivElement>(null);
   const dp = useRef<DPlayer | null>(null);
   const [mvData, setMvData] = useState<any>(null);
@@ -31,16 +32,30 @@ const Video_Player = ({ mvId }: VideoPlayerProps) => {
     if (!mvId) return;
     try {
       const response = await checkMvFavoriteApi(mvId);
-
       const favStatus = response.data === 1 || response.data === true || response.data === "1" || response.data === "已收藏";
       setIsFavorite(favStatus);
-      console.log('初始/兜底收藏状态:', favStatus, 'check接口返回值:', response.data);
     } catch (error) {
       console.error('检查收藏状态失败:', error);
       setIsFavorite(false);
     }
   };
 
+  // 根据MD5获取实际视频URL
+  const getVideoUrlByMd5 = async (md5: string) => {
+    try {
+      const response = await GetFileUrlByMd5Api(md5);
+      if (response.code === 200 && response.data) {
+        return response.data; // 返回实际的视频URL
+      } else {
+        console.error('获取视频URL失败:', response);
+        return null;
+      }
+    } catch (error) {
+      console.error('请求视频URL失败:', error);
+      return null;
+    }
+  };
+
   useEffect(() => {
     const fetchMvData = async () => {
       if (!actualMvId || isNaN(parseInt(actualMvId))) {
@@ -68,10 +83,16 @@ const Video_Player = ({ mvId }: VideoPlayerProps) => {
           }
         }
 
-        // 直接使用返回的视频URL,不再通过MD5获取
+        // 如果存在videoUrl且为MD5格式,需要通过API获取实际URL
         if (targetMv && targetMv.videoUrl) {
-          setVideoUrl(targetMv.videoUrl);
-          console.log('视频URL获取成功:', targetMv.videoUrl);
+          const actualVideoUrl = await getVideoUrlByMd5(targetMv.videoUrl);
+          if (actualVideoUrl) {
+            setVideoUrl(actualVideoUrl);
+            console.log('视频URL获取成功:', actualVideoUrl);
+          } else {
+            console.warn('无法获取视频URL');
+            setVideoUrl(null);
+          }
         } else {
           console.warn('MV无有效视频URL:', targetMv?.videoUrl);
           setVideoUrl(null);
@@ -107,7 +128,7 @@ const Video_Player = ({ mvId }: VideoPlayerProps) => {
             video: {
               url: videoUrl,
               pic: mvData?.coverUrl || 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
-              type: 'auto'
+              type: 'video/mp4'
             },
             autoplay: false,
             theme: '#b74747',
@@ -127,7 +148,7 @@ const Video_Player = ({ mvId }: VideoPlayerProps) => {
 
           dp.current.on('error', (err: any) => {
             console.error('视频播放失败:', err);
-            message.error('视频加载失败,请刷新重试');
+            message.error('视频加载失败,请检查视频URL是否有效');
           });
         } catch (playerErr) {
           console.error('播放器创建失败:', playerErr);
@@ -158,16 +179,16 @@ const Video_Player = ({ mvId }: VideoPlayerProps) => {
       console.error('MV ID无效:', mvData?.id);
       return;
     }
-    
+
     setFavoriteLoading(true);
-    
+
     try {
       const response = await toggleMvFavoriteApi(mvData.id);
       // 先判断接口请求成功
       if (response.code === 200) {
         const resData = response.data;
         console.log('收藏接口返回字符串:', resData);
-        
+
         let newFavStatus = false;
         // 精准匹配后端返回的字符串:收藏成功
         if (resData === "收藏成功") {
@@ -240,17 +261,17 @@ const Video_Player = ({ mvId }: VideoPlayerProps) => {
       </div>
 
       <div className="video-player" style={{ marginBottom: '16px' }}>
-        <div 
-          ref={dpContainer} 
-          style={{ 
-            height: '400px', 
-            width: '100%', 
-            backgroundColor: '#000', 
+        <div
+          ref={dpContainer}
+          style={{
+            height: '400px',
+            width: '100%',
+            backgroundColor: '#000',
             borderRadius: '4px',
             display: 'flex',
             alignItems: 'center',
             justifyContent: 'center'
-          }} 
+          }}
         >
           {!videoUrl && <span style={{ color: '#fff' }}>视频资源未加载</span>}
         </div>

+ 4 - 7
src/pages/layout/pages/Video/index.tsx

@@ -3,18 +3,15 @@ import Rank_Recommend_body_list_Comment from '../find/rank/compomemts/Rank_Recom
 import Rank_Recommend_body_list_Comment_list from '../find/rank/compomemts/Rank_Recommend_body_list_Comment_list'
 import './index.css'
 import Video_Player from './Video_player'
-
 const Video = () => {
-  // 接收路径参数
   const { id } = useParams<{ id: string }>();
-
+  const numericId = id ? parseInt(id, 10) : 0;
   return (
     <div className="video">
-      <Video_Player mvId={id}></Video_Player>
-      <Rank_Recommend_body_list_Comment mvId={id} />
-      <Rank_Recommend_body_list_Comment_list mvId={id} />
+      <Video_Player mvId={numericId}></Video_Player>
+      <Rank_Recommend_body_list_Comment contentId={numericId} type={1} />
+      <Rank_Recommend_body_list_Comment_list contentId={numericId} type={1} />
     </div>
   )
 }
-
 export default Video

+ 69 - 0
src/pages/layout/pages/find/rank/compomemts/CommentInput/index.css

@@ -0,0 +1,69 @@
+.comment-input-container {
+  margin: 30px 0 30px 40px;
+}
+.comment-input-container .comment-input-content {
+  display: flex;
+  margin-top: 20px;
+}
+.comment-input-container .comment-input-content .comment-input-avatar {
+  width: 50px;
+  height: 50px;
+  margin-right: 10px;
+}
+.comment-input-container .comment-input-content .comment-input-box {
+  position: relative;
+  padding-left: 10px;
+  margin-left: 10px;
+  width: 600px;
+}
+.comment-input-container .comment-input-content .comment-input-box .comment-input-button-group {
+  display: flex;
+  justify-content: space-between;
+  line-height: 40px;
+  height: 40px;
+}
+.comment-input-container .comment-input-content .comment-input-box .comment-input-button-group .comment-input-button-left {
+  color: #999999;
+  display: flex;
+}
+.comment-input-container .comment-input-content .comment-input-box .comment-input-button-group .comment-input-button-left .comment-input-button-left-icon {
+  font-size: 20px;
+  margin-right: 10px;
+}
+.comment-input-container .comment-input-content .comment-input-box .comment-input-button-group .comment-input-button-left .comment-input-button-left-text {
+  font-size: 25px;
+}
+.comment-input-container .comment-input-content .comment-input-box .comment-input-button-group .comment-input-button-right {
+  display: flex;
+}
+.comment-input-container .comment-input-content .comment-input-box .comment-input-button-group .comment-input-button-right .comment-input-button-right-text {
+  font-size: 20px;
+  margin-right: 10px;
+  color: #999999;
+}
+.comment-input-container .comment-input-content .comment-input-box .comment-input-button-group .comment-input-button-right .comment-input-button-right-button {
+  margin: auto 0;
+}
+.comment-input-container .comment-input-content .comment-input-box .comment-input-button-group .comment-input-button-right .comment-input-button-right-button .comment-input-button-right-submit {
+  cursor: pointer;
+  width: 60px;
+  height: 30px;
+  background: #4491da;
+  text-align: center;
+  line-height: 30px;
+  border-radius: 3px;
+  color: #ffffff;
+}
+.comment-input-container .comment-input-content .comment-input-box .comment-input-button-group .comment-input-button-right .comment-input-button-right-button .comment-input-button-right-submit:hover {
+  background: #55a4ef;
+}
+.comment-input-container .comment-input-content .comment-input-box::before {
+  content: '';
+  position: absolute;
+  left: 0;
+  top: 10px;
+  border-width: 6px 8px;
+  border-style: solid;
+  border-color: transparent #ffffff transparent transparent;
+  background: none;
+}

+ 72 - 0
src/pages/layout/pages/find/rank/compomemts/CommentInput/index.less

@@ -0,0 +1,72 @@
+// src/components/CommentInput/index.less
+.comment-input-container {
+  margin: 30px 0 30px 40px;
+
+  .comment-input-content {
+    display: flex;
+    margin-top: 20px;
+    .comment-input-avatar {
+      width: 50px;
+      height: 50px;
+      margin-right: 10px;
+    }
+    .comment-input-box {
+      position: relative;
+      padding-left: 10px;
+      margin-left: 10px;
+      width: 600px;
+      .comment-input-button-group {
+        display: flex;
+        justify-content: space-between;
+        line-height: 40px;
+        height: 40px;
+        .comment-input-button-left {
+          color: rgb(153, 153, 153);
+          display: flex;
+          .comment-input-button-left-icon {
+            font-size: 20px;
+            margin-right: 10px;
+          }
+          .comment-input-button-left-text {
+            font-size: 25px;
+          }
+        }
+        .comment-input-button-right {
+          display: flex;
+          .comment-input-button-right-text {
+            font-size: 20px;
+            margin-right: 10px;
+            color: rgb(153, 153, 153);
+          }
+          .comment-input-button-right-button {
+            margin: auto 0;
+            .comment-input-button-right-submit {
+              cursor: pointer;
+              width: 60px;
+              height: 30px;
+              background: rgb(68, 145, 218);
+              text-align: center;
+              line-height: 30px;
+              border-radius: 3px;
+              color: #ffffff;
+              &:hover {
+                background: rgb(85, 164, 239);
+              }
+            }
+          }
+        }
+      }
+    }
+
+    .comment-input-box::before {
+      content: '';
+      position: absolute;
+      left: 0;
+      top: 10px;
+      border-width: 6px 8px;
+      border-style: solid;
+      border-color: transparent #ffffff transparent transparent;
+      background: none;
+    }
+  }
+}

+ 90 - 0
src/pages/layout/pages/find/rank/compomemts/CommentInput/index.tsx

@@ -0,0 +1,90 @@
+import { Image, message } from 'antd'
+import './index.css'
+import TextArea from 'antd/es/input/TextArea'
+import { useState } from 'react'
+import { SmileOutlined } from '@ant-design/icons'
+import { useLocation } from 'react-router-dom'
+import { addCommentByIdType } from '@/apis/comment'
+import { getUserinfo } from '@/utils'
+interface CommentInputProps {
+  contentId?: number
+  parentId?: number | null
+  onSubmit: () => void;
+  type?: number
+}
+
+const CommentInput = ({ contentId, parentId, onSubmit, type }: CommentInputProps) => {
+  const location = useLocation()
+  const [value, setValue] = useState('')
+  const mvData = location.state?.mv || null
+  const [messageApi, contextHolder] = message.useMessage();
+  const user = getUserinfo()
+  const handleSubmit = () => {
+    if (value.trim()) {
+      console.log("提交内容:" + value)
+      console.log("提交内容类型:" + type)
+      console.log("提交内容ID:" + contentId)
+      console.log("提交内容父ID:" + parentId)
+      const src = user.url
+      const username = user.name
+      const res = addCommentByIdType({ contentId, parentId, value, type, src, username })
+      if (res.code != 200) {
+        onSubmit()
+        setValue('')
+      } else {
+        messageApi.open({
+          type: 'error',
+          content: '发送异常',
+        })
+      }
+    }
+  }
+
+  return (
+    <div className="comment-input-container">
+      {contextHolder}
+      <div className="comment-input-content">
+        <div className="comment-input-avatar">
+          <Image
+            src={user.url || 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'}
+            width={50}
+            height={50}
+            preview={false}
+          />
+        </div>
+        <div className="comment-input-box">
+          <TextArea
+            value={value}
+            onChange={(e) => setValue(e.target.value)}
+            placeholder={`对 "${mvData?.mvName || '这个视频'}" 的评论`}
+            autoSize={{ minRows: 3, maxRows: 5 }}
+            style={{ width: '620px' }}
+          />
+          <div className="comment-input-button-group">
+            <div className="comment-input-button-left">
+              <div className="comment-input-button-left-icon">
+                <SmileOutlined />
+              </div>
+
+            </div>
+            <div className="comment-input-button-right">
+              <div className="comment-input-button-right-text">
+                {value.length}/140
+              </div>
+              <div className="comment-input-button-right-button">
+                <div
+                  className="comment-input-button-right-submit"
+                  onClick={handleSubmit}
+                >
+                  评论
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default CommentInput;

+ 22 - 0
src/pages/layout/pages/find/rank/compomemts/CommentItem/index.css

@@ -0,0 +1,22 @@
+/* comment-item.css */
+.comment-item-container {
+  position: relative;
+  margin-bottom: 10px;
+}
+.comment-content-wrapper {
+  display: flex;
+  align-items: flex-start;
+}
+.Rank_Recommend_body_list_Comment_list_content_left {
+  margin-right: 10px;
+}
+.Rank_Recommend_body_list_Comment_list_content_right {
+  flex: 1;
+}
+/* 确保子评论有正确的缩进 */
+.sub-comments-container {
+  margin-left: 20px;
+  /* 或者使用 level 计算的值 */
+  padding-left: 10px;
+  border-left: 1px solid #e8e8e8;
+}

+ 25 - 0
src/pages/layout/pages/find/rank/compomemts/CommentItem/index.less

@@ -0,0 +1,25 @@
+/* comment-item.css */
+.comment-item-container {
+  position: relative;
+  margin-bottom: 10px;
+}
+
+.comment-content-wrapper {
+  display: flex;
+  align-items: flex-start;
+}
+
+.Rank_Recommend_body_list_Comment_list_content_left {
+  margin-right: 10px;
+}
+
+.Rank_Recommend_body_list_Comment_list_content_right {
+  flex: 1;
+}
+
+/* 确保子评论有正确的缩进 */
+.sub-comments-container {
+  margin-left: 20px; /* 或者使用 level 计算的值 */
+  padding-left: 10px;
+  border-left: 1px solid #e8e8e8;
+}

+ 205 - 0
src/pages/layout/pages/find/rank/compomemts/CommentItem/index.tsx

@@ -0,0 +1,205 @@
+// CommentItem.tsx
+import { Image, Dropdown, Menu } from 'antd';
+import { LikeOutlined, DeleteOutlined } from '@ant-design/icons';
+import { useState } from 'react';
+import CommentInput from '../CommentInput';
+import { getCommentListByPid } from '@/apis/comment';
+import { request } from '@/utils';
+
+interface CommentItemProps {
+  item: {
+    id: number;
+    userId: number;
+    contentType: number;
+    src: string;
+    username: string;
+    contentId: number;
+    parentId: number | null;
+    content: string;
+    likeCount: number;
+    replyCount: number;
+    status: number;
+    createTime: string;
+    updateTime: string;
+  };
+  contentId?: number;
+  type?: number;
+  level?: number;
+  likedComments: number[];
+  activeCommentBox: { type: 'reply' | 'main', id?: number } | null;
+  onToggleLike: (commentId: number) => void;
+  onToggleReply: (id: number) => void;
+  onReplySubmit: () => void;
+  onCommentDeleted?: (commentId: number) => void;
+}
+
+const CommentItem = ({
+  item,
+  contentId,
+  type,
+  level = 0,
+  likedComments,
+  activeCommentBox,
+  onToggleLike,
+  onToggleReply,
+  onReplySubmit,
+  onCommentDeleted
+}: CommentItemProps) => {
+  // 展开状态管理
+  const [expanded, setExpanded] = useState(false);
+  const [replies, setReplies] = useState<any[]>([]);
+  const [loadingReplies, setLoadingReplies] = useState(false);
+
+  // 获取子评论
+  const fetchReplies = async () => {
+    if (loadingReplies) return;
+    
+    setLoadingReplies(true);
+    try {
+      const res = await getCommentListByPid(item.id);
+      setReplies(res.data);
+      setExpanded(true);
+    } catch (error) {
+      console.error('获取子评论失败:', error);
+    } finally {
+      setLoadingReplies(false);
+    }
+  };
+
+  // 切换展开状态
+  const toggleExpand = () => {
+    if (expanded) {
+      setExpanded(false);
+    } else {
+      fetchReplies();
+    }
+  };
+
+  // 删除评论
+  const deleteComment = async (commentId: number) => {
+    try {
+      await request.get(`/comment/delete`, { params: { id: commentId } });
+      console.log('评论删除成功');
+      if (onCommentDeleted) {
+        onCommentDeleted(commentId);
+      }
+    } catch (error) {
+      console.error('删除评论失败:', error);
+    }
+  };
+
+  // 计算缩进
+  const marginLeft = level == 1 ? `${level * 20}px` : '0px';
+
+  // 右键菜单
+  const menu = (
+    <Menu>
+      <Menu.Item key="delete" icon={<DeleteOutlined />} danger onClick={() => deleteComment(item.id)}>
+        删除评论
+      </Menu.Item>
+    </Menu>
+  );
+
+  // 阻止右键默认事件
+  const handleContextMenu = (e: React.MouseEvent) => {
+    e.preventDefault();
+  };
+
+  return (
+    <div 
+      className="comment-item-container" 
+      style={{ marginLeft }}
+      onContextMenu={handleContextMenu}
+    >
+      <Dropdown overlay={menu} trigger={['contextMenu']}>
+        <div className="comment-content-wrapper">
+          <div className="Rank_Recommend_body_list_Comment_list_content_left">
+            <Image width={50} src={item.src} preview={false} />
+          </div>
+          <div className="Rank_Recommend_body_list_Comment_list_content_right">
+            <div className="Rank_Recommend_body_list_Comment_list_content_right_top">
+              <div className="Rank_Recommend_body_list_Comment_list_content_right_top_username">
+                {item.username}
+              </div>
+              <div className="Rank_Recommend_body_list_Comment_list_content_right_top_content">
+                {item.content}
+              </div>
+            </div>
+            <div className="Rank_Recommend_body_list_Comment_list_content_right_bottom">
+              <div className="Rank_Recommend_body_list_Comment_list_content_right_bottom_time">
+                {new Date(item.createTime).toLocaleDateString('zh-CN')}
+                {item.replyCount > 0 && (
+                  <div 
+                    className='Rank_Recommend_body_list_Comment_list_content_right_bottom_time_button'
+                    onClick={toggleExpand}
+                    style={{ cursor: 'pointer', marginLeft: '10px' }}
+                  >
+                    {expanded ? `收起 (${replies.length})` : `展开 ${item.replyCount} 条回复`}
+                  </div>
+                )}
+              </div>
+
+              <div className="Rank_Recommend_body_list_Comment_list_content_right_bottom_right">
+                <div className="Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like">
+                  <div 
+                    className={`Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like_icon ${likedComments.includes(item.id) ? 'liked' : ''}`}
+                    onClick={() => onToggleLike(item.id)}
+                    style={{ cursor: 'pointer', color: likedComments.includes(item.id) ? '#1890ff' : 'inherit' }}
+                  >
+                    <LikeOutlined />
+                    {item.likeCount === 0 ? '' : item.likeCount}
+                  </div>
+                  <div
+                    className="Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like_button"
+                    onClick={() => onToggleReply(item.id)}
+                  >
+                    回复
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </Dropdown>
+
+      {/* 显示回复框 - 在评论下方 */}
+      {activeCommentBox?.type === 'reply' && activeCommentBox.id === item.id && (
+        <div className="comment-reply-box">
+          <CommentInput
+            contentId={contentId}
+            parentId={item.id}
+            onSubmit={onReplySubmit}
+            type={type}
+          />
+        </div>
+      )}
+
+      {/* 展开的子评论 */}
+      {expanded && (
+        <div className="sub-comments-container">
+          {loadingReplies ? (
+            <div>加载中...</div>
+          ) : (
+            replies.map((reply, index) => (
+              <CommentItem
+                key={`${reply.id}-${index}`}
+                item={reply}
+                contentId={contentId}
+                type={type}
+                level={level + 1}
+                likedComments={likedComments}
+                activeCommentBox={activeCommentBox}
+                onToggleLike={onToggleLike}
+                onToggleReply={onToggleReply}
+                onReplySubmit={onReplySubmit}
+                onCommentDeleted={onCommentDeleted}
+              />
+            ))
+          )}
+        </div>
+      )}
+    </div>
+  );
+};
+
+export default CommentItem;

+ 3 - 4
src/pages/layout/pages/find/rank/compomemts/RankPlaylist/index.tsx

@@ -1,4 +1,3 @@
-// src/pages/layout/pages/find/rank/components/RankPlaylist/index.tsx
 import Rank_Recommend_body_right from '../../compomemts/Rank_Recommend_body_right'
 import Rank_Recommend_body_list from '../../compomemts/Rank_Recommend_body_list'
 import Rank_Recommend_body_list_Comment from '../../compomemts/Rank_Recommend_body_list_Comment'
@@ -6,11 +5,11 @@ import Rank_Recommend_body_list_Comment_list from '../../compomemts/Rank_Recomme
 
 const RankPlaylist = () => {
   return (
-    <div>
+    <div style={{ marginBottom: '40px' }}>
       <Rank_Recommend_body_right />
       <Rank_Recommend_body_list />
-      <Rank_Recommend_body_list_Comment />
-      <Rank_Recommend_body_list_Comment_list />
+      <Rank_Recommend_body_list_Comment contentId={"123"} type={2} />
+      <Rank_Recommend_body_list_Comment_list contentId={"111"} type={2} />
     </div>
   )
 }

+ 1 - 67
src/pages/layout/pages/find/rank/compomemts/Rank_Recommend_body_list_Comment/index.css

@@ -1,76 +1,10 @@
 .Rank_Recommend_body_list_Comment {
   margin: 30px 0 30px 40px;
 }
-.Rank_Recommend_body_list_Comment .Rank_Recommend_body_list_Comment_title {
+.Rank_Recommend_body_list_Comment .comment-input-title {
   margin-right: 30px;
   font-size: 20px;
   height: 30px;
   line-height: 30px;
   border-bottom: 2px solid red;
 }
-.Rank_Recommend_body_list_Comment .Rank_Recommend_body_list_Comment_content {
-  display: flex;
-  margin-top: 20px;
-}
-.Rank_Recommend_body_list_Comment .Rank_Recommend_body_list_Comment_content .comment-box {
-  position: relative;
-  padding-left: 10px;
-  /* 避免文字贴着箭头 */
-  margin-left: 10px;
-  width: 600px;
-}
-.Rank_Recommend_body_list_Comment .Rank_Recommend_body_list_Comment_content .comment-box .Rank_Recommend_body_list_Comment_button {
-  display: flex;
-  justify-content: space-between;
-  line-height: 40px;
-  height: 40px;
-}
-.Rank_Recommend_body_list_Comment .Rank_Recommend_body_list_Comment_content .comment-box .Rank_Recommend_body_list_Comment_button .Rank_Recommend_body_list_Comment_button_left {
-  color: #999999;
-  display: flex;
-}
-.Rank_Recommend_body_list_Comment .Rank_Recommend_body_list_Comment_content .comment-box .Rank_Recommend_body_list_Comment_button .Rank_Recommend_body_list_Comment_button_left .Rank_Recommend_body_list_Comment_button_left_icon {
-  font-size: 20px;
-  margin-right: 10px;
-}
-.Rank_Recommend_body_list_Comment .Rank_Recommend_body_list_Comment_content .comment-box .Rank_Recommend_body_list_Comment_button .Rank_Recommend_body_list_Comment_button_left .Rank_Recommend_body_list_Comment_button_left_text {
-  font-size: 25px;
-}
-.Rank_Recommend_body_list_Comment .Rank_Recommend_body_list_Comment_content .comment-box .Rank_Recommend_body_list_Comment_button .Rank_Recommend_body_list_Comment_button_right {
-  display: flex;
-}
-.Rank_Recommend_body_list_Comment .Rank_Recommend_body_list_Comment_content .comment-box .Rank_Recommend_body_list_Comment_button .Rank_Recommend_body_list_Comment_button_right .Rank_Recommend_body_list_Comment_button_right_text {
-  font-size: 20px;
-  margin-right: 10px;
-  color: #999999;
-}
-.Rank_Recommend_body_list_Comment .Rank_Recommend_body_list_Comment_content .comment-box .Rank_Recommend_body_list_Comment_button .Rank_Recommend_body_list_Comment_button_right .Rank_Recommend_body_list_Comment_button_right_button {
-  margin: auto 0;
-}
-.Rank_Recommend_body_list_Comment .Rank_Recommend_body_list_Comment_content .comment-box .Rank_Recommend_body_list_Comment_button .Rank_Recommend_body_list_Comment_button_right .Rank_Recommend_body_list_Comment_button_right_button .Rank_Recommend_body_list_Comment_button_right_button_submit {
-  cursor: pointer;
-  width: 60px;
-  height: 30px;
-  background: #4491da;
-  text-align: center;
-  line-height: 30px;
-  border-radius: 3px;
-  color: #ffffff;
-}
-.Rank_Recommend_body_list_Comment .Rank_Recommend_body_list_Comment_content .comment-box .Rank_Recommend_body_list_Comment_button .Rank_Recommend_body_list_Comment_button_right .Rank_Recommend_body_list_Comment_button_right_button .Rank_Recommend_body_list_Comment_button_right_button_submit:hover {
-  background: #55a4ef;
-}
-.Rank_Recommend_body_list_Comment .Rank_Recommend_body_list_Comment_content .comment-box::before {
-  content: '';
-  position: absolute;
-  left: 0;
-  top: 10px;
-  /* 调整垂直位置 */
-  border-width: 6px 8px;
-  /* 控制大小 */
-  border-style: solid;
-  border-color: transparent #ffffff transparent transparent;
-  /* 小尖角朝左 */
-  background: none;
-  /* 确保没有背景色干扰 */
-}

+ 3 - 65
src/pages/layout/pages/find/rank/compomemts/Rank_Recommend_body_list_Comment/index.less

@@ -1,73 +1,11 @@
 .Rank_Recommend_body_list_Comment {
   margin: 30px 0 30px 40px;
-  .Rank_Recommend_body_list_Comment_title {
+
+  .comment-input-title {
     margin-right: 30px;
     font-size: 20px;
     height: 30px;
     line-height: 30px;
     border-bottom: 2px solid red;
   }
-  .Rank_Recommend_body_list_Comment_content {
-    display: flex;
-    margin-top: 20px;
-    .comment-box {
-      position: relative;
-      padding-left: 10px; /* 避免文字贴着箭头 */
-      margin-left: 10px;
-      width: 600px;
-      .Rank_Recommend_body_list_Comment_button {
-        display: flex;
-        justify-content: space-between;
-
-        line-height: 40px;
-        height: 40px;
-        .Rank_Recommend_body_list_Comment_button_left {
-          color: rgb(153, 153, 153);
-          display: flex;
-          .Rank_Recommend_body_list_Comment_button_left_icon {
-            font-size: 20px;
-            margin-right: 10px;
-          }
-          .Rank_Recommend_body_list_Comment_button_left_text {
-            font-size: 25px;
-          }
-        }
-        .Rank_Recommend_body_list_Comment_button_right {
-          display: flex;
-          .Rank_Recommend_body_list_Comment_button_right_text {
-            font-size: 20px;
-            margin-right: 10px;
-            color: rgb(153, 153, 153);
-          }
-          .Rank_Recommend_body_list_Comment_button_right_button {
-            margin: auto 0;
-            .Rank_Recommend_body_list_Comment_button_right_button_submit {
-              cursor: pointer;
-              width: 60px;
-              height: 30px;
-              background: rgb(68, 145, 218);
-              text-align: center;
-              line-height: 30px;
-              border-radius: 3px;
-              color: #ffffff;
-              &:hover {
-                background: rgb(85, 164, 239);
-              }
-            }
-          }
-        }
-      }
-    }
-
-    .comment-box::before {
-      content: '';
-      position: absolute;
-      left: 0;
-      top: 10px; /* 调整垂直位置 */
-      border-width: 6px 8px; /* 控制大小 */
-      border-style: solid;
-      border-color: transparent #ffffff transparent transparent; /* 小尖角朝左 */
-      background: none; /* 确保没有背景色干扰 */
-    }
-  }
-}
+}

+ 14 - 61
src/pages/layout/pages/find/rank/compomemts/Rank_Recommend_body_list_Comment/index.tsx

@@ -1,74 +1,27 @@
-import { Image } from 'antd';
+import CommentInput from '../CommentInput';
 import './index.css';
-import TextArea from 'antd/es/input/TextArea';
-import { useState } from 'react';
-import { SmileOutlined } from '@ant-design/icons';
-import { useLocation, useParams } from 'react-router-dom';
 
 interface CommentProps {
-  mvId?: string;
+  contentId?: number;
+  type: number;
 }
 
-const Rank_Recommend_body_list_Comment = ({ mvId }: CommentProps) => {
-  const location = useLocation();
-  const params = useParams<{ id: string }>();
-  const actualMvId = mvId || params.id;
-  const [value, setValue] = useState('');
-  
-  // 获取MV信息用于评论
-  const mvData = location.state?.mv || null;
+const Rank_Recommend_body_list_Comment = ({ contentId, type }: CommentProps) => {
+
 
   const handleSubmitComment = () => {
-    console.log('提交评论:', { value, mvId: actualMvId });
-    // 这里可以添加提交评论的API调用
-    setValue(''); // 清空输入框
-  };
+    window.location.reload();
+  }
 
   return (
     <div className="Rank_Recommend_body_list_Comment">
-      <div className="Rank_Recommend_body_list_Comment_title">评论</div>
-      <div className="Rank_Recommend_body_list_Comment_content">
-        <div className="Rank_Recommend_body_list_Comment_content_Img">
-          <Image
-            src="https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"
-            width={50}
-            height={50}
-            preview={false}
-          />
-        </div>
-        <div className="comment-box">
-          <TextArea
-            value={value}
-            onChange={(e) => setValue(e.target.value)}
-            placeholder={`对 "${mvData?.mvName || '这个视频'}" 的评论`}
-            autoSize={{ minRows: 3, maxRows: 5 }}
-            style={{ width: '620px' }}
-          />
-          <div className="Rank_Recommend_body_list_Comment_button">
-            <div className="Rank_Recommend_body_list_Comment_button_left">
-              <div className="Rank_Recommend_body_list_Comment_button_left_icon">
-                <SmileOutlined />
-              </div>
-              <div className="Rank_Recommend_body_list_Comment_button_left_text">
-                @
-              </div>
-            </div>
-            <div className="Rank_Recommend_body_list_Comment_button_right">
-              <div className="Rank_Recommend_body_list_Comment_button_right_text">
-                {value.length}/140
-              </div>
-              <div className="Rank_Recommend_body_list_Comment_button_right_button">
-                <div 
-                  className='Rank_Recommend_body_list_Comment_button_right_button_submit'
-                  onClick={handleSubmitComment}
-                >
-                  评论
-                </div>
-              </div>
-            </div>
-          </div>
-        </div>
-      </div>
+      <div className="comment-input-title">评论</div>
+      <CommentInput
+        contentId={contentId}
+        onSubmit={handleSubmitComment}
+        type={type}
+        parentId={null}
+      />
     </div>
   );
 };

+ 48 - 7
src/pages/layout/pages/find/rank/compomemts/Rank_Recommend_body_list_Comment_list/indes.css

@@ -10,33 +10,74 @@
 }
 .Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_content {
   margin-top: 20px;
-  display: flex;
   padding-bottom: 20px;
   border-bottom: 1px solid #d7d1d1;
+  position: relative;
+}
+.Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_content .comment-content-wrapper {
+  display: flex;
 }
-.Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_content .Rank_Recommend_body_list_Comment_list_content_right {
+.Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_content .comment-content-wrapper .Rank_Recommend_body_list_Comment_list_content_left {
+  width: 50px;
+  flex-shrink: 0;
+}
+.Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_content .comment-content-wrapper .Rank_Recommend_body_list_Comment_list_content_right {
   margin-left: 20px;
   display: flex;
   flex-direction: column;
   justify-content: space-between;
   width: 640px;
+  flex: 1;
 }
-.Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_content .Rank_Recommend_body_list_Comment_list_content_right .Rank_Recommend_body_list_Comment_list_content_right_top {
+.Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_content .comment-content-wrapper .Rank_Recommend_body_list_Comment_list_content_right .Rank_Recommend_body_list_Comment_list_content_right_top {
   display: flex;
+  flex-direction: column;
+  margin-bottom: 10px;
+}
+.Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_content .comment-content-wrapper .Rank_Recommend_body_list_Comment_list_content_right .Rank_Recommend_body_list_Comment_list_content_right_top .Rank_Recommend_body_list_Comment_list_content_right_top_username {
+  font-weight: bold;
+  margin-bottom: 5px;
+  color: #333;
 }
-.Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_content .Rank_Recommend_body_list_Comment_list_content_right .Rank_Recommend_body_list_Comment_list_content_right_bottom {
+.Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_content .comment-content-wrapper .Rank_Recommend_body_list_Comment_list_content_right .Rank_Recommend_body_list_Comment_list_content_right_top .Rank_Recommend_body_list_Comment_list_content_right_top_content {
+  line-height: 1.5;
+  color: #666;
+}
+.Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_content .comment-content-wrapper .Rank_Recommend_body_list_Comment_list_content_right .Rank_Recommend_body_list_Comment_list_content_right_bottom {
   display: flex;
   justify-content: space-between;
+  align-items: center;
+}
+.Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_content .comment-content-wrapper .Rank_Recommend_body_list_Comment_list_content_right .Rank_Recommend_body_list_Comment_list_content_right_bottom .Rank_Recommend_body_list_Comment_list_content_right_bottom_time {
+  color: #999;
+  font-size: 12px;
+  display: flex;
+  gap: 10px;
 }
-.Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_content .Rank_Recommend_body_list_Comment_list_content_right .Rank_Recommend_body_list_Comment_list_content_right_bottom .Rank_Recommend_body_list_Comment_list_content_right_bottom_right .Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like {
+.Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_content .comment-content-wrapper .Rank_Recommend_body_list_Comment_list_content_right .Rank_Recommend_body_list_Comment_list_content_right_bottom .Rank_Recommend_body_list_Comment_list_content_right_bottom_time .Rank_Recommend_body_list_Comment_list_content_right_bottom_time_button {
+  color: #519ff2;
+  cursor: pointer;
+}
+.Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_content .comment-content-wrapper .Rank_Recommend_body_list_Comment_list_content_right .Rank_Recommend_body_list_Comment_list_content_right_bottom .Rank_Recommend_body_list_Comment_list_content_right_bottom_right .Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like {
   display: flex;
+  align-items: center;
 }
-.Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_content .Rank_Recommend_body_list_Comment_list_content_right .Rank_Recommend_body_list_Comment_list_content_right_bottom .Rank_Recommend_body_list_Comment_list_content_right_bottom_right .Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like .Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like_icon {
+.Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_content .comment-content-wrapper .Rank_Recommend_body_list_Comment_list_content_right .Rank_Recommend_body_list_Comment_list_content_right_bottom .Rank_Recommend_body_list_Comment_list_content_right_bottom_right .Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like .Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like_icon {
   color: #0088fe;
   margin-right: 20px;
+  cursor: pointer;
+}
+.Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_content .comment-content-wrapper .Rank_Recommend_body_list_Comment_list_content_right .Rank_Recommend_body_list_Comment_list_content_right_bottom .Rank_Recommend_body_list_Comment_list_content_right_bottom_right .Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like .Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like_icon:hover {
+  color: #1890ff;
 }
-.Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_content .Rank_Recommend_body_list_Comment_list_content_right .Rank_Recommend_body_list_Comment_list_content_right_bottom .Rank_Recommend_body_list_Comment_list_content_right_bottom_right .Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like .Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like_button {
+.Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_content .comment-content-wrapper .Rank_Recommend_body_list_Comment_list_content_right .Rank_Recommend_body_list_Comment_list_content_right_bottom .Rank_Recommend_body_list_Comment_list_content_right_bottom_right .Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like .Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like_button {
   color: #6f6f6f;
+  cursor: pointer;
+  padding: 4px 8px;
+  border-radius: 4px;
+}
+.Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_content .comment-content-wrapper .Rank_Recommend_body_list_Comment_list_content_right .Rank_Recommend_body_list_Comment_list_content_right_bottom .Rank_Recommend_body_list_Comment_list_content_right_bottom_right .Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like .Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like_button:hover {
+  background-color: #f0f0f0;
 }
 .Rank_Recommend_body_list_Comment_list .Rank_Recommend_body_list_Comment_list_Pagination {
   margin-top: 20px;

+ 88 - 26
src/pages/layout/pages/find/rank/compomemts/Rank_Recommend_body_list_Comment_list/indes.less

@@ -1,5 +1,7 @@
+// indes.less
 .Rank_Recommend_body_list_Comment_list {
   padding: 40px;
+
   .Rank_Recommend_body_list_Comment_list_ttitle {
     color: rgb(0, 0, 0);
     font-weight: bolder;
@@ -7,49 +9,109 @@
     height: 40px;
     border-bottom: 1px solid rgb(125, 121, 121);
   }
+
   .Rank_Recommend_body_list_Comment_list_content {
     margin-top: 20px;
-    display: flex;
     padding-bottom: 20px;
     border-bottom: 1px solid rgb(215, 209, 209);
-    .Rank_Recommend_body_list_Comment_list_content_right {
-      margin-left: 20px;
-      display: flex;
-      flex-direction: column; // 纵向排列内容
-      justify-content: space-between; // 可选:自动分配上下空间
-      width: 640px;
-      .Rank_Recommend_body_list_Comment_list_content_right_top {
-        display: flex;
-        .Rank_Recommend_body_list_Comment_list_content_right_top_username {
-        }
-        .Rank_Recommend_body_list_Comment_list_content_right_top_content {
-        }
+    position: relative; // 为回复框定位做准备
+
+    .comment-content-wrapper {
+      display: flex; // 保持左右布局
+
+      .Rank_Recommend_body_list_Comment_list_content_left {
+        width: 50px;
+        flex-shrink: 0; // 防止压缩
       }
-      .Rank_Recommend_body_list_Comment_list_content_right_bottom {
+
+      .Rank_Recommend_body_list_Comment_list_content_right {
+        margin-left: 20px;
         display: flex;
-        //水平靠下对齐
+        flex-direction: column;
         justify-content: space-between;
-        .Rank_Recommend_body_list_Comment_list_content_right_bottom_time {
+        width: 640px;
+        flex: 1; // 占据剩余空间
+
+        .Rank_Recommend_body_list_Comment_list_content_right_top {
+          display: flex;
+          flex-direction: column; // 用户名和内容垂直排列
+          margin-bottom: 10px;
+
+          .Rank_Recommend_body_list_Comment_list_content_right_top_username {
+            font-weight: bold;
+            margin-bottom: 5px;
+            color: #333;
+          }
+
+          .Rank_Recommend_body_list_Comment_list_content_right_top_content {
+            line-height: 1.5;
+            color: #666;
+          }
         }
-        .Rank_Recommend_body_list_Comment_list_content_right_bottom_right {
-          .Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like {
+
+        .Rank_Recommend_body_list_Comment_list_content_right_bottom {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+
+          .Rank_Recommend_body_list_Comment_list_content_right_bottom_time {
+            color: #999;
+            font-size: 12px;
             display: flex;
-            .Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like_icon {
-              color: rgb(0, 136, 254);
-              //向左20px
-              margin-right: 20px;
+            gap: 10px;
+
+            .Rank_Recommend_body_list_Comment_list_content_right_bottom_time_button {
+              color: rgb(81, 159, 242);
+              cursor: pointer;
             }
-            .Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like_button {
-              color: rgb(111, 111, 111);
+          }
+
+          .Rank_Recommend_body_list_Comment_list_content_right_bottom_right {
+            .Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like {
+              display: flex;
+              align-items: center;
+
+              .Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like_icon {
+                color: rgb(0, 136, 254);
+                margin-right: 20px;
+                cursor: pointer;
+
+                &:hover {
+                  color: #1890ff;
+                }
+              }
+
+              .Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like_button {
+                color: rgb(111, 111, 111);
+                cursor: pointer;
+                padding: 4px 8px;
+                border-radius: 4px;
+
+                &:hover {
+                  background-color: #f0f0f0;
+                }
+              }
             }
           }
         }
       }
     }
+
+    // // 回复框样式
+    // .comment-reply-box {
+    //   margin-top: 15px;
+    //   margin-left: 70px; // 与头像对齐
+    //   width: calc(100% - 70px); // 减去左边距
+    //   padding: 15px;
+    //   background-color: #fafafa;
+    //   border-radius: 4px;
+    //   border: 1px solid #e8e8e8;
+    // }
   }
+
   .Rank_Recommend_body_list_Comment_list_Pagination {
     margin-top: 20px;
     display: flex;
-    justify-content: center; 
+    justify-content: center;
   }
-}
+}

+ 166 - 81
src/pages/layout/pages/find/rank/compomemts/Rank_Recommend_body_list_Comment_list/index.tsx

@@ -1,79 +1,174 @@
-import { Image, type PaginationProps } from 'antd';
+import { Empty } from 'antd';
 import './indes.css';
-import { LikeOutlined } from '@ant-design/icons';
 import { useEffect, useState } from 'react';
-import { useLocation, useParams } from 'react-router-dom';
+import CommentItem from '../CommentItem';
+import { getCommentListByIdType, addLikeCount, cancelLikeCount } from '@/apis/comment';
 
 interface CommentListProps {
-  mvId?: string;
+  contentId?: number;
+  type?: number
 }
 
-interface Comment {
+// API 响应的数据结构
+interface ApiComment {
   id: number;
+  userId: number;
+  contentType: number;
   src: string;
   username: string;
+  contentId: number;
+  parentId: number | null;
   content: string;
-  time: string;
-  like: number;
+  likeCount: number;
+  replyCount: number;
+  status: number;
+  createTime: string;
+  updateTime: string;
 }
 
-const Rank_Recommend_body_list_Comment_list = ({ mvId }: CommentListProps) => {
-  const location = useLocation();
-  const params = useParams<{ id: string }>();
-  const actualMvId = mvId || params.id;
-  const [comments, setComments] = useState<Comment[]>([]);
-  const [loading, setLoading] = useState(true);
+interface ApiResponse {
+  code: number;
+  message: string;
+  data: ApiComment[];
+}
 
-  // 获取MV信息
-  const mvData = location.state?.mv || null;
+const Rank_Recommend_body_list_Comment_list = ({ contentId, type }: CommentListProps) => {
+  const actualMvId = contentId;
+  const [comments, setComments] = useState<ApiComment[]>([]);
+  const [loading, setLoading] = useState(true);
 
   useEffect(() => {
     const fetchComments = async () => {
       if (actualMvId) {
         try {
-          const mockComments: Comment[] = [
-            {
-              id: 0,
-              src: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
-              username: '爱音乐的用户',
-              content: `对 "${mvData?.mvName || '这个MV'}" 的精彩评论`,
-              time: '2024-01-04',
-              like: 15,
-            },
-            {
-              id: 1,
-              src: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
-              username: '音乐爱好者',
-              content: '这个MV真的很好看,制作精良!',
-              time: '2024-01-03',
-              like: 8,
-            },
-          ];
-
-          setComments(mockComments);
+          const res: ApiResponse = await getCommentListByIdType({
+            contentId: actualMvId,
+            type
+          });
+          setComments(res.data);
         } catch (error) {
           console.error('获取评论失败:', error);
         } finally {
           setLoading(false);
         }
+      } else {
+        setLoading(false); // 如果没有 contentId,也设置为非加载状态
       }
     };
 
     fetchComments();
-  }, [actualMvId, mvData?.mvName]);
-
-  const itemRender: PaginationProps['itemRender'] = (
-    _,
-    type,
-    originalElement
-  ) => {
-    if (type === 'prev') {
-      return <a>上一页</a>;
+  }, [actualMvId, type]);
+
+  const [activeCommentBox, setActiveCommentBox] = useState<{ type: 'reply' | 'main', id?: number } | null>(null);
+
+  const toggleReply = (id: number) => {
+    if (activeCommentBox && activeCommentBox.type === 'reply' && activeCommentBox.id === id) {
+      setActiveCommentBox(null);
+    } else {
+      // 否则显示这个回复框
+      setActiveCommentBox({ type: 'reply', id });
     }
-    if (type === 'next') {
-      return <a>下一页</a>;
+  };
+
+  const handleReplySubmit = () => {
+    setActiveCommentBox(null);
+    // 提交回复后重新获取评论列表
+    const fetchComments = async () => {
+      if (actualMvId) {
+        try {
+          setLoading(true);
+          const res: ApiResponse = await getCommentListByIdType({
+            contentId: actualMvId,
+            type
+          });
+          setComments(res.data);
+        } catch (error) {
+          console.error('获取评论失败:', error);
+        } finally {
+          setLoading(false);
+        }
+      }
+    };
+    fetchComments();
+  };
+
+  // 删除评论后的处理
+  const handleCommentDeleted = (commentId: number) => {
+    // 重新获取评论列表以更新状态
+    const fetchComments = async () => {
+      if (actualMvId) {
+        try {
+          setLoading(true);
+          const res: ApiResponse = await getCommentListByIdType({
+            contentId: actualMvId,
+            type
+          });
+          setComments(res.data);
+        } catch (error) {
+          console.error('获取评论失败:', error);
+        } finally {
+          setLoading(false);
+        }
+      }
+    };
+    fetchComments();
+  };
+
+  // 处理点赞功能
+  const handleLike = async (commentId: number) => {
+    try {
+      // 调用API进行点赞
+      const res = await addLikeCount(commentId);
+      
+      // 更新本地状态
+      setComments(prevComments => 
+        prevComments.map(comment => 
+          comment.id === commentId 
+            ? { ...comment, likeCount: comment.likeCount + 1 } 
+            : comment
+        )
+      );
+      
+      console.log('点赞成功:', res);
+    } catch (error) {
+      console.error('点赞失败:', error);
+    }
+  };
+
+  // 处理取消点赞功能
+  const handleCancelLike = async (commentId: number) => {
+    try {
+      // 调用API取消点赞
+      const res = await cancelLikeCount(commentId);
+      
+      // 更新本地状态
+      setComments(prevComments => 
+        prevComments.map(comment => 
+          comment.id === commentId 
+            ? { ...comment, likeCount: Math.max(0, comment.likeCount - 1) } 
+            : comment
+        )
+      );
+      
+      console.log('取消点赞成功:', res);
+    } catch (error) {
+      console.error('取消点赞失败:', error);
+    }
+  };
+
+  // 点赞按钮状态管理
+  const [likedComments, setLikedComments] = useState<number[]>([]);
+
+  const toggleLike = async (commentId: number) => {
+    if (likedComments.includes(commentId)) {
+      // 如果已经点赞,取消点赞
+      await handleCancelLike(commentId);
+      setLikedComments(prev => prev.filter(id => id !== commentId));
+    } else {
+      // 如果没有点赞,进行点赞
+      await handleLike(commentId);
+      setLikedComments(prev => [...prev, commentId]);
     }
-    return originalElement;
   };
 
   if (loading) {
@@ -85,42 +180,32 @@ const Rank_Recommend_body_list_Comment_list = ({ mvId }: CommentListProps) => {
       <div className="Rank_Recommend_body_list_Comment_list_ttitle">
         精彩评论 ({comments.length})
       </div>
-      {comments.map((item, index) => (
-        <div
-          className="Rank_Recommend_body_list_Comment_list_content"
-          key={`${item.id}-${index}`}
-        >
-          <div className="Rank_Recommend_body_list_Comment_list_content_left">
-            <Image width={50} src={item.src} preview={false} />
-          </div>
-          <div className="Rank_Recommend_body_list_Comment_list_content_right">
-            <div className="Rank_Recommend_body_list_Comment_list_content_right_top">
-              <div className="Rank_Recommend_body_list_Comment_list_content_right_top_username">
-                {item.username}
-              </div>
-              <div className="Rank_Recommend_body_list_Comment_list_content_right_top_content">
-                {item.content}
-              </div>
-            </div>
-            <div className="Rank_Recommend_body_list_Comment_list_content_right_bottom">
-              <div className="Rank_Recommend_body_list_Comment_list_content_right_bottom_time">
-                {item.time}
-              </div>
-              <div className="Rank_Recommend_body_list_Comment_list_content_right_bottom_right">
-                <div className="Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like">
-                  <div className="Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like_icon">
-                    <LikeOutlined />
-                    {item.like === 0 ? '' : item.like}
-                  </div>
-                  <div className="Rank_Recommend_body_list_Comment_list_content_right_bottom_right_like_button">
-                    回复
-                  </div>
-                </div>
-              </div>
-            </div>
+      
+      {comments.length > 0 ? (
+        comments.map((item, index) => (
+          <div
+            className="Rank_Recommend_body_list_Comment_list_content"
+            key={`${item.id}-${index}`}
+          >
+            <CommentItem
+              item={item}
+              contentId={actualMvId}
+              type={type}
+              level={0}
+              likedComments={likedComments}
+              activeCommentBox={activeCommentBox}
+              onToggleLike={toggleLike}
+              onToggleReply={toggleReply}
+              onReplySubmit={handleReplySubmit}
+              onCommentDeleted={handleCommentDeleted}
+            />
           </div>
+        ))
+      ) : (
+        <div style={{ padding: '20px 0' }}>
+          <Empty description="暂无评论" />
         </div>
-      ))}
+      )}
     </div>
   );
 };