<template>
  <div class="post-detail">
    <button @click="goBack" class="back-btn">返回主页</button>

    <h2 class="post-title">{{ post?.title }}</h2>
    <p class="post-info">
      作者: {{ post?.username || post?.userId }} |
      发布时间: {{ formatDateTime(post?.createdAt) }}
    </p>
    <p class="post-content" style="white-space: pre-wrap">{{ post?.content }}</p>

    <!-- 点赞 收藏 举报 按钮 -->
    <div class="post-actions">
      <button @click="toggleLike" :class="{ active: liked }" class="btn-like">
        {{ liked ? "已点赞" : "点赞" }} ({{ likeCount }})
      </button>
      <button @click="toggleFavorite" :class="{ active: favorited }" class="btn-favorite">
        {{ favorited ? "已收藏" : "收藏" }}
      </button>
      <button @click="openReportDialog" class="btn-report">
        举报
      </button>
    </div>

    <hr />

    <h3>评论区</h3>

    <div v-if="loadingComments" class="loading">加载评论中...</div>
    <div v-else>
      <ul class="comments-list">
        <li v-for="comment in rootComments" :key="comment.id" class="comment-item">
          <div class="comment-main">
            <div class="comment-header">
              <b>{{ comment.username || ("用户ID: " + comment.userId) }}</b>
              <span v-if="comment.createdAt" class="comment-time"
              >评论时间 {{ formatDateTime(comment.createdAt) }}</span
              >
              <button
                  v-if="comment.userId == userId"
                  @click="deleteComment(comment.id)"
                  class="btn-delete"
                  title="删除评论"
              >
                删除
              </button>

              <button @click="toggleReplyBox(comment.id)" class="btn-reply">
                {{ replyingTo === comment.id ? "取消回复" : "回复" }}
              </button>

              <button @click="toggleRepliesCollapse(comment.id)" class="btn-collapse">
                {{ repliesCollapsed[comment.id] ? "展开回复" : "收起回复" }}
              </button>
            </div>

            <p class="comment-content" style="white-space: pre-wrap">{{ comment.content }}</p>

            <div v-if="replyingTo === comment.id" class="reply-box">
              <textarea
                  v-model="replyContent"
                  rows="2"
                  placeholder="回复内容"
              ></textarea>
              <button class="btn-submit" @click="submitReply(comment.id)">提交回复</button>
            </div>
          </div>

          <ul
              v-if="!repliesCollapsed[comment.id] && flattenReplies[comment.id]?.length"
              class="replies-list"
          >
            <li
                v-for="reply in flattenReplies[comment.id]"
                :key="reply.id"
                class="comment-reply"
            >
              <div class="comment-header">
                <b>{{ reply.username || ("用户ID: " + reply.userId) }}</b>
                <span class="comment-time"
                >回复时间 {{ formatDateTime(reply.createdAt) }}</span
                >

                <span class="reply-to" v-if="reply.parentCommentId">
                  回复 <b>{{ rootCommentUsernames[comment.id] }}</b>
                </span>

                <button
                    v-if="reply.userId == userId"
                    @click="deleteComment(reply.id)"
                    class="btn-delete"
                    title="删除回复"
                >
                  删除
                </button>

                <button @click="toggleReplyBox(reply.id)" class="btn-reply">
                  {{ replyingTo === reply.id ? "取消回复" : "回复" }}
                </button>
              </div>

              <p class="comment-content" style="white-space: pre-wrap">
                {{ reply.content }}
              </p>

              <div v-if="replyingTo === reply.id" class="reply-box">
                <textarea
                    v-model="replyContent"
                    rows="2"
                    placeholder="回复内容"
                ></textarea>
                <button class="btn-submit" @click="submitReply(reply.id)">
                  提交回复
                </button>
              </div>
            </li>
          </ul>
        </li>
      </ul>

      <hr />

      <h4>发表评论</h4>
      <textarea
          v-model="newComment"
          rows="3"
          style="width: 100%"
          placeholder="请输入评论内容"
          class="new-comment-textarea"
      ></textarea>
      <button class="btn-submit" @click="submitComment">提交评论</button>
    </div>

    <el-dialog v-model="reportDialogVisible" title="举报帖子" width="400px">
      <textarea
          v-model="reportReason"
          placeholder="请输入举报原因"
          rows="4"
          style="width: 100%"
      ></textarea>
      <span slot="footer" class="dialog-footer">
        <el-button @click="reportDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="submitReport">提交举报</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, computed, onMounted } from "vue";
import axios from "axios";
import { useRoute, useRouter } from "vue-router";
import { ElMessage, ElMessageBox } from "element-plus";
import dayjs from "dayjs";

const formatDateTime = (isoString) => {
  if (!isoString) return "";
  return dayjs(isoString).format("YYYY年MM月DD日 HH:mm:ss");
};

const route = useRoute();
const router = useRouter();

const postId = Number(route.params.id);
const post = ref(null);
const comments = ref([]);
const loadingComments = ref(false);
const userId = localStorage.getItem("userId");

const newComment = ref("");
const replyingTo = ref(null);
const replyContent = ref("");
const repliesCollapsed = ref({});

// 点赞收藏举报相关
const liked = ref(false);
const likeCount = ref(0);
const favorited = ref(false);
const reportDialogVisible = ref(false);
const reportReason = ref("");

const fetchPost = async () => {
  try {
    const res = await axios.get(`http://localhost:8080/forum/post/${postId}`);
    post.value = res.data;
    likeCount.value = res.data.likeCount || 0;
  } catch (error) {
    ElMessage.error("加载帖子详情失败");
    router.back();
  }
};

const fetchComments = async () => {
  loadingComments.value = true;
  try {
    const res = await axios.get(`http://localhost:8080/forum/comments/${postId}`);
    comments.value = res.data;
  } catch (error) {
    ElMessage.error("加载评论失败");
  } finally {
    loadingComments.value = false;
  }
};

const fetchLikeStatus = async () => {
  if (!userId) return;
  try {
    const res = await axios.get(`http://localhost:8080/forum/post/like/status`, {
      params: { userId, postId }
    });
    liked.value = res.data.liked;
  } catch (error) {
    console.error("查询点赞状态失败", error);
  }
};

const fetchFavoriteStatus = async () => {
  if (!userId) return;
  try {
    const res = await axios.get(`http://localhost:8080/forum/post/favorite/status`, {
      params: { userId, postId }
    });
    favorited.value = res.data.favorited;
  } catch (error) {
    console.error("查询收藏状态失败", error);
  }
};

const toggleRepliesCollapse = (commentId) => {
  repliesCollapsed.value[commentId] = !repliesCollapsed.value[commentId];
};

const goBack = () => {
  router.back();
};

const submitComment = async () => {
  const content = newComment.value.trim();
  if (!content) {
    ElMessage.warning("请输入评论内容");
    return;
  }
  try {
    await axios.post("http://localhost:8080/forum/comment", {
      postId,
      userId,
      content,
      parentCommentId: null,
    });
    ElMessage.success("评论成功");
    newComment.value = "";
    fetchComments();
  } catch (error) {
    ElMessage.error("发表评论失败");
  }
};

const toggleReplyBox = (commentId) => {
  if (replyingTo.value === commentId) {
    replyingTo.value = null;
    replyContent.value = "";
  } else {
    replyingTo.value = commentId;
    replyContent.value = "";
  }
};

const submitReply = async (parentCommentId) => {
  const content = replyContent.value.trim();
  if (!content) {
    ElMessage.warning("请输入回复内容");
    return;
  }
  try {
    await axios.post("http://localhost:8080/forum/comment", {
      postId,
      userId,
      content,
      parentCommentId,
    });
    ElMessage.success("回复成功");
    replyingTo.value = null;
    replyContent.value = "";
    fetchComments();
  } catch (error) {
    ElMessage.error("回复失败");
  }
};

const deleteComment = async (commentId) => {
  try {
    await ElMessageBox.confirm("确定删除此评论吗?", "提示", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning",
    });
    await axios.delete(`http://localhost:8080/forum/comment/${commentId}`);
    ElMessage.success("删除成功");
    fetchComments();
  } catch (error) {
    if (error !== "cancel") {
      ElMessage.error("删除失败");
    }
  }
};

const toggleLike = async () => {
  if (!userId) {
    ElMessage.warning("请先登录");
    return;
  }
  try {
    if (!liked.value) {
      await axios.post("http://localhost:8080/forum/post/like", { userId, postId });
      liked.value = true;
      likeCount.value++;
      ElMessage.success("点赞成功");
    } else {
      await axios.delete("http://localhost:8080/forum/post/like", { params: { userId, postId } });
      liked.value = false;
      likeCount.value--;
      ElMessage.success("取消点赞成功");
    }
  } catch {
    ElMessage.error("点赞操作失败");
  }
};

const toggleFavorite = async () => {
  if (!userId) {
    ElMessage.warning("请先登录");
    return;
  }
  try {
    if (!favorited.value) {
      await axios.post("http://localhost:8080/forum/post/favorite", { userId, postId });
      favorited.value = true;
      ElMessage.success("收藏成功");
    } else {
      await axios.delete("http://localhost:8080/forum/post/favorite", { params: { userId, postId } });
      favorited.value = false;
      ElMessage.success("取消收藏成功");
    }
  } catch {
    ElMessage.error("收藏操作失败");
  }
};

const openReportDialog = () => {
  if (!userId) {
    ElMessage.warning("请先登录");
    return;
  }
  reportReason.value = "";
  reportDialogVisible.value = true;
};

const submitReport = async () => {
  if (!reportReason.value.trim()) {
    ElMessage.warning("请输入举报原因");
    return;
  }
  try {
    await axios.post("http://localhost:8080/forum/post/report", {
      reporterId: userId,
      postId,
      reason: reportReason.value,
    });
    ElMessage.success("举报成功，管理员会尽快处理");
    reportDialogVisible.value = false;
  } catch {
    ElMessage.error("举报失败");
  }
};

// 计算一级评论（parentCommentId === null）
const rootComments = computed(() =>
    comments.value
        .filter((c) => !c.parentCommentId)
        .sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt))
);

// flattenReplies: 二级及以上回复折叠到一级评论
const flattenReplies = computed(() => {
  const map = {};
  rootComments.value.forEach((root) => {
    map[root.id] = [];
  });
  comments.value.forEach((c) => {
    if (c.parentCommentId) {
      let parentId = c.parentCommentId;
      let current = comments.value.find((cc) => cc.id === parentId);
      while (current && current.parentCommentId) {
        parentId = current.parentCommentId;
        current = comments.value.find((cc) => cc.id === parentId);
      }
      if (map[parentId]) {
        map[parentId].push(c);
      }
    }
  });
  Object.values(map).forEach((list) =>
      list.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt))
  );
  return map;
});

const rootCommentUsernames = computed(() => {
  const map = {};
  rootComments.value.forEach((root) => {
    map[root.id] = root.username || `用户ID: ${root.userId}`;
  });
  return map;
});

onMounted(() => {
  fetchPost();
  fetchComments();
  fetchLikeStatus();
  fetchFavoriteStatus();
});
</script>

<style scoped>
.post-detail {
  max-width: 800px;
  margin: auto;
  padding: 20px;
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
  color: #222;
  background: #f9f9f9;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgb(0 0 0 / 0.1);
}

.back-btn {
  background: none;
  border: none;
  color: #409eff;
  font-size: 16px;
  cursor: pointer;
  margin-bottom: 10px;
  padding: 0;
  transition: color 0.3s;
}
.back-btn:hover {
  color: #66b1ff;
}

.post-title {
  margin-bottom: 8px;
  color: #303133;
  font-weight: 700;
}

.post-info {
  margin-bottom: 20px;
  color: #909399;
  font-size: 14px;
}

.post-content {
  background: white;
  padding: 16px;
  border-radius: 6px;
  margin-bottom: 30px;
  white-space: pre-wrap;
  line-height: 1.5;
  box-shadow: inset 0 0 8px rgb(0 0 0 / 0.03);
}

.post-actions {
  margin: 10px 0 20px;
  display: flex;
  gap: 12px;
}
.post-actions button {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 14px;
  background-color: #f0f2f5;
  border: 1px solid #dcdfe6;
  border-radius: 18px;
  font-size: 14px;
  font-weight: 600;
  color: #606266;
  cursor: pointer;
  transition: all 0.3s ease;
  user-select: none;
}

.btn-like.active,
.btn-favorite.active {
  color: #f56c6c;
  font-weight: bold;
}

.comments-list,
.replies-list {
  list-style-type: none;
  padding-left: 0;
  margin: 0;
}

.comment-item {
  background: white;
  border-radius: 6px;
  padding: 14px 20px;
  margin-bottom: 16px;
  box-shadow: 0 1px 3px rgb(0 0 0 / 0.1);
}

.comment-main {
  position: relative;
}

.comment-header {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  font-size: 14px;
  margin-bottom: 8px;
}

.comment-header b {
  color: #409eff;
  font-weight: 600;
}

.comment-time {
  color: #909399;
  font-size: 12px;
}

.reply-to {
  color: #606266;
  font-size: 12px;
  margin-left: 4px;
}

.comment-content {
  font-size: 15px;
  color: #606266;
  line-height: 1.5;
  margin: 0;
  white-space: pre-wrap;
  padding-left: 4px;
}

.btn-delete,
.btn-reply,
.btn-submit,
.btn-collapse {
  background: none;
  border: none;
  color: #409eff;
  cursor: pointer;
  padding: 2px 6px;
  border-radius: 4px;
  font-size: 13px;
  transition: background-color 0.3s;
  user-select: none;
}

.btn-delete {
  color: #f56c6c;
}
.btn-delete:hover {
  background-color: #fde2e2;
}

.btn-reply:hover,
.btn-submit:hover,
.btn-collapse:hover {
  background-color: #ecf5ff;
  color: #66b1ff;
}

.reply-box {
  margin-top: 8px;
}

.reply-box textarea {
  width: 100%;
  padding: 4px 8px;
  font-size: 14px;
  border-radius: 4px;
  border: 1px solid #dcdfe6;
  resize: vertical;
  min-height: 42px;
}

.reply-box .btn-submit {
  margin-top: 6px;
  font-weight: 600;
}

.replies-list {
  margin-top: 10px;
  padding-left: 30px;
  border-left: 2px solid #ebeef5;
}

.comment-reply {
  background: #f5f7fa;
  border-radius: 6px;
  padding: 10px 16px;
  margin-bottom: 12px;
  box-shadow: inset 0 1px 3px rgb(0 0 0 / 0.03);
}

.new-comment-textarea {
  margin-bottom: 10px;
  border-radius: 6px;
  border: 1px solid #dcdfe6;
  padding: 8px 10px;
  font-size: 15px;
  resize: vertical;
}

.btn-submit {
  background-color: #409eff;
  color: white;
  border-radius: 4px;
  padding: 8px 18px;
  font-weight: 600;
  transition: background-color 0.3s;
}
.btn-submit:hover {
  background-color: #66b1ff;
}

.loading {
  font-size: 16px;
  color: #909399;
  text-align: center;
  padding: 20px 0;
}

.post-actions button:hover {
  background-color: #e6f7ff;
  border-color: #91d5ff;
  color: #1890ff;
}

.post-actions button.active {
  background-color: #bae7ff;
  border-color: #40a9ff;
  color: #096dd9;
  box-shadow: 0 0 6px rgb(24 144 255 / 0.6);
}

/* 点赞按钮单独颜色 */
.btn-like {
  color: #fa541c;
  border-color: #ffa39e;
}
.btn-like.active {
  background-color: #ffccc7;
  border-color: #ff4d4f;
  color: #a8071a;
  box-shadow: 0 0 6px rgb(255 77 79 / 0.8);
}

/* 收藏按钮单独颜色 */
.btn-favorite {
  color: #faad14;
  border-color: #ffe58f;
}
.btn-favorite.active {
  background-color: #fff7e6;
  border-color: #ffc53d;
  color: #ad6800;
  box-shadow: 0 0 6px rgb(255 197 0 / 0.8);
}

/* 举报按钮采用警告色 */
.btn-report {
  color: #f5222d;
  border-color: #ffccc7;
}
.btn-report:hover {
  background-color: #fff1f0;
  border-color: #ff4d4f;
  color: #a8071a;
  box-shadow: 0 0 6px rgb(255 77 79 / 0.8);
}
</style>
根据上面的代码，帮我写一个“我的帖子”页面，管理删除自己帖子、收藏和点赞