帖子列表和查看帖子详情

main
lee-zt 1 month ago
parent a637c4eaec
commit d856624130

@ -37,69 +37,59 @@
</template> </template>
<script setup lang="js" name="PostPage"> <script setup lang="js" name="PostPage">
import { ref } from 'vue'; import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { usePostListStore } from '@/stores/postlist.js';
const categories = ref(['全部', '学习', '娱乐', '二手交易']); const categories = ref(['全部', '学习', '娱乐', '二手交易']);
const selectedCategory = ref('全部'); const selectedCategory = ref('全部');
const posts = ref([ const postListStore = usePostListStore();
{
id: 1,
category: '学习',
title: '如何高效学习?',
summary: '分享一些学习技巧...',
avatar: require('@/assets/default-avatar/boy_1.png'),
likes: 1200,
comments: 10,
favorites: 100,
},
{
id: 2,
category: '娱乐',
title: '最近的热门电影推荐',
summary: '看看这些电影吧...',
avatar: require('@/assets/default-avatar/girl_1.png'),
likes: 800,
comments: 5,
favorites: 50,
},
{
id: 3,
category: '二手交易',
title: '出售二手书籍',
summary: '价格优惠,欢迎咨询...',
avatar: require('@/assets/default-avatar/boy_2.png'),
likes: 300,
comments: 2,
favorites: 20,
},
{
id: 4,
category: '学习',
title: '考研经验分享',
summary: '考研路上的一些心得...',
avatar: require('@/assets/default-avatar/girl_3.png'),
likes: 1500,
comments: 20,
favorites: 200,
},
]);
const filteredPosts = ref(posts.value);
const router = useRouter(); const router = useRouter();
const selectCategory = (category) => { //
const filteredPosts = computed(() => {
if (selectedCategory.value === '全部') return postListStore.posts;
return postListStore.posts.filter(post => post.category === selectedCategory.value);
});
//
const selectCategory = async (category) => {
selectedCategory.value = category; selectedCategory.value = category;
filteredPosts.value = postListStore.resetList();
category === '全部' await postListStore.getList({});
? posts.value
: posts.value.filter((post) => post.category === category);
}; };
//
const goToPostDetail = (postId) => { const goToPostDetail = (postId) => {
router.push({ name: 'PostDetail', params: { id: postId } }); router.push({ name: 'PostDetail', params: { id: postId } });
}; };
//
const handleScroll = async () => {
const scrollContainer = document.documentElement;
if (
scrollContainer.scrollTop + window.innerHeight >= scrollContainer.scrollHeight - 10 &&
!postListStore.loading &&
!postListStore.finished
) {
await postListStore.getList({});
}
};
onMounted(async () => {
//
await postListStore.getList({});
window.addEventListener('scroll', handleScroll);
});
onUnmounted(() => {
window.removeEventListener('scroll', handleScroll);
});
//
watch(selectedCategory, () => {
window.scrollTo(0, 0);
});
</script> </script>
<style scoped> <style scoped>

@ -0,0 +1,93 @@
import { defineStore } from "pinia";
import request from "@/utils/request";
export const usePostDetailStore = defineStore("postDetail", {
state: () => ({
post: null, // 帖子主要信息
comments: [], // 评论列表
userInfo: null, // 用户信息
totalComments: 0, // 评论总数
likeCount: 0, // 点赞数
commentCount: 0, // 评论数
favoriteCount: 0, // 收藏数
viewCount: 0, // 浏览数
isLike: false, // 是否点赞
loading: false, // 加载状态
}),
actions: {
setPost(post) {
this.post = post;
},
setComments(comments) {
this.comments = comments;
this.totalComments = comments.length;
},
setUserInfo(userInfo) {
this.userInfo = userInfo;
},
addComment(comment) {
this.comments.push(comment);
this.totalComments += 1;
},
async fetchPostDetail(postId, { lastVal = Date.now(), offset = 0, size = 10 } = {}) {
this.loading = true;
try {
// 获取帖子详情
const postRes = await request.get(`/post/detail/${postId}`);
if (postRes.code === 200 && postRes.data) {
const {
id,
image,
title,
content,
likeCount,
commentCount,
favoriteCount,
viewCount,
isLike,
userId,
userName,
userAvatar,
createTime
} = postRes.data;
// 主要帖子信息
this.post = {
postId: id,
title,
content,
createTime,
};
// 用户信息
this.userInfo = {
userId,
userName,
userAvatar: userAvatar || image || null,
followers:1234,//先预设粉丝占位
};
// 其余字段
this.likeCount = likeCount;
this.commentCount = commentCount;
this.favoriteCount = favoriteCount;
this.viewCount = viewCount;
this.isLike = isLike;
}
// 获取评论列表
const commentRes = await request.post('/comment/list', {
lastVal,
offset,
size,
postId
});
if (commentRes.code === 200) {
this.setComments(commentRes.data.records || []);
}
} finally {
this.loading = false;
}
},
},
});

@ -0,0 +1,78 @@
import {defineStore} from 'pinia';
import axios from 'axios';
import request from '@/utils/request';
export const usePostListStore = defineStore('postList', {
state: () => ({
posts: [], // 帖子列表
total: 0, // 帖子总数
page: 1, // 当前页码
pageSize: 10, // 每页帖子数
lastVal: Date.now(), // 用于滚动分页的时间戳
offset: 0, // 偏移量
loading: false, // 加载状态
finished: false, // 是否加载完全部
}),
actions: {
setPosts(posts) {
this.posts = posts;
},
setTotal(total) {
this.total = total;
},
setPage(page) {
this.page = page;
},
setPageSize(pageSize) {
this.pageSize = pageSize;
},
addPost(post) {
this.posts.push(post);
this.total += 1; // 更新总数
},
removePost(postId) {
this.posts = this.posts.filter(post => post.id !== postId);
this.total -= 1; // 更新总数
},
async getList({ lastVal = this.lastVal, offset = this.offset, size = this.pageSize } = {}) {
if (this.loading || this.finished) return;
this.loading = true;
try {
const res = await request.post('/post/list', { lastVal, offset, size });
if (res.code === 200) {
const { records, lastVal: newLastVal, offset: newOffset, size: newSize } = res.data;
if (records.length > 0) {
// 字段映射
const mappedRecords = records.map(post => ({
id: post.id,
avatar: post.userAvatar || post.image || require('@/assets/default-avatar/boy_1.png'),
title: post.title,
summary: post.content ? post.content.slice(0, 40) + (post.content.length > 40 ? '...' : '') : '',
likes: post.likeCount,
comments: post.commentCount,
favorites: post.favoriteCount,
category: post.category || '全部',
createTime: post.createTime,
userName: post.userName,
}));
this.posts = [...this.posts, ...mappedRecords];
this.lastVal = newLastVal;
this.offset = newOffset;
this.pageSize = newSize;
}
if (records.length < size) {
this.finished = true; // 没有更多数据
}
}
} finally {
this.loading = false;
}
},
resetList() {
this.posts = [];
this.lastVal = Date.now();
this.offset = 0;
this.finished = false;
}
},
});

@ -1,10 +1,10 @@
<template> <template>
<div class="post-detail-container"> <div class="post-detail-container">
<!-- 作者信息栏 --> <!-- 作者信息栏可保留或移除 -->
<div class="author-info"> <div class="author-info">
<img :src="author.avatar" alt="头像" class="author-avatar" /> <img :src="author.userAvatar" alt="头像" class="author-avatar" />
<div class="author-details"> <div class="author-details">
<h3 class="author-name">{{ author.name }}</h3> <h3 class="author-name">{{ author.userName }}</h3>
<p class="author-stats">粉丝数{{ author.followers }}</p> <p class="author-stats">粉丝数{{ author.followers }}</p>
<button @click="toggleFollow" class="follow-button"> <button @click="toggleFollow" class="follow-button">
{{ isFollowing ? '取消关注' : '关注' }} {{ isFollowing ? '取消关注' : '关注' }}
@ -14,16 +14,16 @@
<!-- 帖子内容 --> <!-- 帖子内容 -->
<div class="post-content"> <div class="post-content">
<img :src="author.avatar" alt="作者头像" class="post-author-avatar" /> <img :src="author.userAvatar" alt="作者头像" class="post-author-avatar" />
<h1 class="post-title">{{ postTitle }}</h1> <h1 class="post-title">{{ postDetailStore.post?.title }}</h1>
<p class="post-body">{{ postContent }}</p> <p class="post-body">{{ postDetailStore.post?.content }}</p>
<div class="post-stats"> <div class="post-stats">
<span> 热度 {{ postStats.likes }}</span> <span> 热度 {{ postDetailStore.post?.likeCount ?? 0 }}</span>
<span> 点赞 {{ postStats.favorites }}</span> <span> 点赞 {{ postDetailStore.post?.favoriteCount ?? 0 }}</span>
<span> 评论 {{ postStats.comments }}</span> <span> 评论 {{ postDetailStore.post?.commentCount ?? 0 }}</span>
</div> </div>
<div class="post-time"> <div class="post-time">
发布时间{{ postTime }} 发布时间{{ postDetailStore.post?.createTime ? formatTime(postDetailStore.post.createTime) : '' }}
</div> </div>
</div> </div>
@ -31,14 +31,14 @@
<div class="comments-section"> <div class="comments-section">
<h2 class="comments-title">评论</h2> <h2 class="comments-title">评论</h2>
<ul class="comments-list"> <ul class="comments-list">
<li v-for="(comment, index) in comments" :key="index" class="comment-item"> <li v-for="comment in postDetailStore.comments" :key="comment.id" class="comment-item">
<img :src="comment.avatar" alt="评论者头像" class="comment-avatar" /> <img :src="comment.userAvatar || require('@/assets/default-avatar/boy_1.png')" alt="评论者头像" class="comment-avatar" />
<div class="comment-content"> <div class="comment-content">
<p class="comment-name">{{ comment.name }}</p> <!-- 评论者名字 --> <p class="comment-name">{{ comment.userName }}</p>
<p class="comment-text">{{ comment.text }}</p> <p class="comment-text">{{ comment.content }}</p>
<div class="comment-meta"> <div class="comment-meta">
<span class="comment-time">{{ comment.time }}</span> <span class="comment-time">{{ comment.createTime ? formatTime(comment.createTime) : '' }}</span>
<span class="comment-likes"> {{ comment.likes }}</span> <span class="comment-likes"> {{ comment.likeCount ?? 0 }}</span>
</div> </div>
</div> </div>
</li> </li>
@ -60,70 +60,41 @@
<script setup lang="js" name="PostDetail"> <script setup lang="js" name="PostDetail">
import { ref, onMounted } from 'vue'; import { ref, onMounted } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { usePostDetailStore } from '@/stores/postdetail';
const route = useRoute(); const route = useRoute();
const postId = ref(route.params.id); const postDetailStore = usePostDetailStore();
const postTitle = ref('');
const postContent = ref('');
const newComment = ref(''); const newComment = ref('');
// //
const author = ref({ const author = postDetailStore.post?.author ;
avatar: require('@/assets/default-avatar/boy_4.png'),
name: '珈人1号',
followers: 1234,
});
//
const postStats = ref({
likes: 1200,
favorites: 300,
comments: 45,
});
//
const postTime = ref('2025年4月20日 14:30');
//
const comments = ref([
{
avatar: require('@/assets/default-avatar/girl_1.png'),
name: '评论者1',
text: '这是第一条评论。',
time: '2025年4月20日 15:00',
likes: 10,
},
{
avatar: require('@/assets/default-avatar/boy_2.png'),
name: '评论者2',
text: '这是第二条评论。',
time: '2025年4月20日 15:30',
likes: 5,
},
]);
const isFollowing = ref(false); const isFollowing = ref(false);
const toggleFollow = () => { const toggleFollow = () => {
isFollowing.value = !isFollowing.value; isFollowing.value = !isFollowing.value;
}; };
//
function formatTime(timeStr) {
const date = new Date(timeStr);
return `${date.getFullYear()}${date.getMonth() + 1}${date.getDate()}${date.getHours()}:${date.getMinutes().toString().padStart(2, '0')}`;
}
//
const sendComment = () => { const sendComment = () => {
if (newComment.value.trim()) { if (newComment.value.trim()) {
comments.value.push({ postDetailStore.addComment({
avatar: require('@/assets/default-avatar/boy_1.png'), userAvatar: require('@/assets/default-avatar/boy_1.png'),
name: '新评论者', userName: '新评论者',
text: newComment.value, content: newComment.value,
time: new Date().toLocaleString(), createTime: new Date().toISOString(),
likes: 0, likeCount: 0,
}); });
newComment.value = ''; newComment.value = '';
} }
}; };
onMounted(() => { onMounted(() => {
postTitle.value = `帖子标题 ${postId.value}`; postDetailStore.fetchPostDetail(route.params.id);
postContent.value = `这是帖子 ${postId.value} 的内容,展示帖子的详细信息。`;
}); });
</script> </script>

Loading…
Cancel
Save