aijinan-app-newVersion/src/components/pageComment copy.vue
2025-05-14 17:25:59 +08:00

381 lines
9.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="comment">
<div class="comment-scroll">
<van-list
v-model:loading="loading"
:finished="finished"
finished-text="没有更多评论了"
@load="loadMore"
>
<div class="scroll-main" id="dataListComment">
<div class="comment-card" v-for="(item, index) in getCommentList" :key="index">
<div class="comment-card-main">
<div class="headImg">
<img v-if="item.headImg" :src="item.headImg" alt />
<img v-else :src="defaultAvatar" alt />
</div>
<span class="top-name">{{item.userName||'游客'}}:&nbsp;&nbsp;</span>
<span class="content-bottom">{{item.text}}</span>
</div>
</div>
</div>
</van-list>
</div>
<div class="comment-input">
<img :src="defaultAvatar"/>
<form @submit.prevent="submitComment">
<van-search
class="input-class"
v-model="commentText"
type="text"
placeholder="我来说几句......"
clearable
background="#ededed"
left-icon
@search="submitComment"
/>
<canvas id="thumsCanvas" width="200" height="1000"></canvas>
<div class="iconShare">
<img src="../assets/img/like.svg" alt @click="clickLikeThumb" />
</div>
</form>
</div>
</div>
</template>
<script setup>
import {ref, onMounted, watch, onUnmounted} from 'vue';
import {commentList, addComment} from '../api/index';
import {getCommentLike} from '../api/detail';
import {showNotify} from 'vant';
import defaultAvatar from '../assets/img/logo.png';
import ThumbsUpAni from '../utils/canvas';
const getCommentList = ref([]);
const commentText = ref('');
const loading = ref(false);
const finished = ref(false);
const page = ref(1);
const pageSize = ref(10);
let thumbsUpAnimation = null;
let thumbsUpInterval = null;
const clickDebounce = ref(false);
const props = defineProps({
sceneData: {
type: Object,
default: () => ({})
}
});
// 点赞功能
const clickLikeThumb = async () => {
if (clickDebounce.value) return;
clickDebounce.value = true;
try {
const res = await getCommentLike({
sceneId: props.sceneData.id
});
if (res.code === 0) {
// 播放点赞动画
if (!thumbsUpAnimation) {
thumbsUpAnimation = new ThumbsUpAni();
}
thumbsUpAnimation.start();
// showNotify({ type: 'success', message: '点赞成功' });
}
} catch (error) {
console.error('点赞失败:', error);
// showNotify({ type: 'danger', message: '点赞失败,请稍后重试' });
} finally {
// 300ms后重置防抖标志
setTimeout(() => {
clickDebounce.value = false;
}, 300);
}
};
// 加载评论列表
const loadMore = async () => {
console.log('loadMore被调用当前场景ID:', props.sceneData?.id);
if (!props.sceneData?.id) {
console.log('场景ID不存在终止加载评论');
loading.value = false;
finished.value = true;
return;
}
if (loading.value) {
console.log('正在加载中,忽略此次加载请求');
return;
}
loading.value = true;
console.log('开始加载评论列表,页码:', page.value, '每页数量:', pageSize.value);
try {
const res = await commentList({
sceneId: props.sceneData.id,
page: page.value,
size: pageSize.value
});
if (res && res.code === 0) {
const processedComments = initCommentLikeStatus(res.data || []);
if (page.value === 1) {
getCommentList.value = processedComments;
} else {
getCommentList.value.push(...processedComments);
}
if (!res.data || res.data.length < pageSize.value) {
finished.value = true;
console.log("没有更多评论数据,设置完成状态");
} else {
page.value += 1;
console.log("还有更多评论,页码增加到:", page.value);
}
} else {
// API返回错误码
console.error("评论列表API返回错误:", res);
finished.value = true;
loading.value = false;
if (res) {
showNotify({ type: 'warning', message: res.msg || '获取评论失败' });
}
}
} catch (error) {
console.error('获取评论列表失败:', error);
showNotify({ type: 'danger', message: '获取评论失败' });
finished.value = true;
} finally {
loading.value = false;
console.log('评论加载完成loading:', loading.value, 'finished:', finished.value);
}
};
// 提交评论
const submitComment = async () => {
if (!commentText.value.trim()) {
showNotify({ type: 'warning', message: '请输入评论内容' });
return;
}
try {
const formData = new FormData();
formData.append('sceneId', props.sceneData.id);
formData.append('text', commentText.value);
const res = await addComment(formData);
if (res.code === 0) {
showNotify({ type: 'success', message: '评论成功' });
commentText.value = '';
// 重新加载评论列表
page.value = 1;
finished.value = false;
getCommentList.value = [];
await loadMore();
}
} catch (error) {
console.error('提交评论失败:', error);
showNotify({ type: 'danger', message: '评论失败,请稍后重试' });
}
};
// 初始化评论列表时,添加点赞状态
const initCommentLikeStatus = (comments) => {
if (!comments) return [];
return comments.map(comment => {
const storageKey = `comment_liked_${comment.id}`;
const isLiked = localStorage.getItem(storageKey) === 'true';
return {
...comment,
isLiked,
likeCount: comment.likeCount || 0
};
});
};
// 父组件调用的加载数据方法
const loadData = () => {
console.log('loadData被调用当前场景ID:', props.sceneData?.id);
if (!props.sceneData?.id) {
console.log('场景ID不存在无法加载评论');
loading.value = false;
finished.value = true;
return;
}
// 强制重置状态,无论是否已有数据都重新加载
console.log('重置评论列表状态,准备重新加载数据');
page.value = 1;
finished.value = false;
loading.value = false; // 确保loading为false避免loadMore中的loading检查阻止加载
getCommentList.value = []; // 清空现有数据
// 立即执行loadMore不需要延迟
loadMore();
};
// 暴露方法给父组件
defineExpose({
loadData
});
// 格式化时间
const formatTime = (time) => {
if (!time) return '';
const date = new Date(time);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
};
// 组件卸载时清理
onUnmounted(() => {
if (thumbsUpInterval) {
clearInterval(thumbsUpInterval);
thumbsUpInterval = null;
}
if (thumbsUpAnimation) {
thumbsUpAnimation = null;
}
});
</script>
<style lang="scss" scoped>
.comment {
height: 100%;
.comment-scroll {
height: calc(100vh - 175px);
overflow: scroll;
.scroll-main {
height: 100%;
.comment-card {
padding: 10px 20px;
.comment-card-main {
display: inline-block;
padding: 5px 10px;
width: auto;
background-color: #EEEEEE;
border-radius: 10px;
.headImg {
display: inline-block;
vertical-align: middle;
width: 30px;
height: 30px;
img {
width: 100%;
height: 100%;
border-radius: 50%;
}
}
.top-name {
margin-left: 10px;
font-size: 16px;
color: #777882;
}
.content-bottom {
font-family: MicrosoftYaHei-Bold;
font-size: 16px;
color: rgba(0,0,0,80%);
line-height: 19px;
letter-spacing: 0px;
}
}
}
}
}
.comment-input {
position: fixed;
bottom: 0;
display: flex;
padding: 0 10px;
width: 100%;
justify-content: space-between;
align-items: center;
height: 50px;
background-color: #fff;
z-index: 1;
img {
width: 40px;
height: 40px;
border-radius: 50%;
}
form {
display: flex;
width: 85%;
justify-content: space-between;
align-items: center;
.iconShare {
width: 35px;
height: 35px;
img {
width: 100%;
height: 100%;
}
}
.input-class.van-search {
padding: 0;
width: 85%;
.van-search__content {
background-color: rgba(255,255,255,0.3);
border-radius: 15px;
color: #454545;
.van-cell {
font-size: 12px !important;
padding: 5px 7px;
}
}
}
}
}
}
#thumsCanvas {
position: fixed;
bottom: 50px;
right: 0;
width: 100px;
margin: auto;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: transparent !important;
pointer-events: none;
z-index: 2;
}
</style>
<style lang="scss">
.van-pull-refresh__track {
height: 100% !important;
}
</style>