fix: youhua
This commit is contained in:
@@ -20,10 +20,13 @@
|
||||
class="comment-input"
|
||||
type="text"
|
||||
v-model="commentText"
|
||||
:disabled="sending"
|
||||
placeholder="说点什么吧..."
|
||||
placeholder-class="input-placeholder"
|
||||
/>
|
||||
<button class="send-btn" @tap="handleSend">发送</button>
|
||||
<button class="send-btn" :class="{ 'is-disabled': sending }" :disabled="sending" @tap="handleSend">
|
||||
{{ sending ? '发送中...' : '发送' }}
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -35,6 +38,10 @@ const props = defineProps({
|
||||
initialAction: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
sending: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
@@ -62,19 +69,28 @@ const handleAction = (action) => {
|
||||
};
|
||||
|
||||
const handleSend = () => {
|
||||
if (!commentText.value.trim()) {
|
||||
const content = commentText.value.trim();
|
||||
if (!content) {
|
||||
uni.showToast({
|
||||
title: '请输入评论内容',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (props.sending) return;
|
||||
emit('send-comment', {
|
||||
action: currentAction.value,
|
||||
content: commentText.value
|
||||
content
|
||||
});
|
||||
commentText.value = ''; // 发送后清空
|
||||
};
|
||||
|
||||
const resetComment = () => {
|
||||
commentText.value = '';
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
resetComment
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -162,7 +178,11 @@ const handleSend = () => {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.send-btn.is-disabled {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.send-btn::after {
|
||||
border: none;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -37,7 +37,7 @@ const props = defineProps({
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(['need-login']);
|
||||
const emit = defineEmits(['need-login', 'like-change']);
|
||||
const userStore = useUserStore();
|
||||
const isLoggedIn = computed(() => !!userStore.token || !!userStore.userInfo?.nickName);
|
||||
|
||||
@@ -70,6 +70,11 @@ const handleLike = async () => {
|
||||
} else {
|
||||
currentLikes.value -= 1;
|
||||
}
|
||||
emit('like-change', {
|
||||
id: props.comment.id,
|
||||
isLiked: isLiked.value,
|
||||
likes: currentLikes.value
|
||||
});
|
||||
|
||||
try {
|
||||
// 调用点赞接口 (点赞和取消点赞为同一个接口)
|
||||
@@ -85,7 +90,6 @@ const handleLike = async () => {
|
||||
page: 'rating_detail'
|
||||
}
|
||||
});
|
||||
uni.showToast({ title: '操作成功', icon: 'success' });
|
||||
} catch (error) {
|
||||
// 接口调用失败,回滚 UI 状态
|
||||
isLiked.value = !isLiked.value;
|
||||
@@ -94,6 +98,11 @@ const handleLike = async () => {
|
||||
} else {
|
||||
currentLikes.value -= 1;
|
||||
}
|
||||
emit('like-change', {
|
||||
id: props.comment.id,
|
||||
isLiked: isLiked.value,
|
||||
likes: currentLikes.value
|
||||
});
|
||||
uni.showToast({ title: '操作失败', icon: 'none' });
|
||||
} finally {
|
||||
isLiking = false;
|
||||
|
||||
@@ -47,7 +47,9 @@
|
||||
|
||||
<!-- 你的态度 -->
|
||||
<AttitudePanel
|
||||
ref="attitudePanelRef"
|
||||
:initial-action="currentAction"
|
||||
:sending="isSendingComment"
|
||||
@action-change="handleActionChange"
|
||||
@send-comment="handleSendComment"
|
||||
/>
|
||||
@@ -89,18 +91,32 @@
|
||||
<!-- <text class="filter-icon"></text> -->
|
||||
</view>
|
||||
|
||||
<view class="comment-list" style="min-height: 400rpx;">
|
||||
<view class="comment-list">
|
||||
<view v-if="commentLoading && !comments.length" class="comment-state">
|
||||
<text class="comment-state-title">评论加载中...</text>
|
||||
<text class="comment-state-desc">正在拉取大家的锐评</text>
|
||||
</view>
|
||||
<view v-else-if="commentError && !comments.length" class="comment-state">
|
||||
<text class="comment-state-title">评论加载失败</text>
|
||||
<text class="comment-state-desc">{{ commentError }}</text>
|
||||
<button class="comment-state-btn" @tap="retryLoadComments">重新加载</button>
|
||||
</view>
|
||||
<view v-else-if="!comments.length" class="comment-state">
|
||||
<text class="comment-state-title">还没有评论</text>
|
||||
<text class="comment-state-desc">来发第一条锐评,带动一下讨论气氛</text>
|
||||
</view>
|
||||
<CommentItem
|
||||
v-for="(comment, index) in comments"
|
||||
:key="comment.id"
|
||||
:comment="comment"
|
||||
@need-login="openLoginPopup"
|
||||
@like-change="handleCommentLikeChange"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 加载更多 -->
|
||||
<view class="load-more">
|
||||
<text>{{ loading ? '加载中...' : (hasMore ? '上拉加载更多' : '没有更多了') }}</text>
|
||||
<view v-if="comments.length" class="load-more">
|
||||
<text>{{ commentLoadText }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -127,14 +143,22 @@ import { getShareReward } from "@/api/system";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
const userStore = useUserStore();
|
||||
const statusBarHeight = ref(getStatusBarHeight() || 44);
|
||||
const loading = ref(false);
|
||||
const hasMore = ref(true);
|
||||
const currentPage = ref(1);
|
||||
const currentAction = ref('');
|
||||
const successPopupRef = ref(null);
|
||||
const loginPopupRef = ref(null);
|
||||
const attitudePanelRef = ref(null);
|
||||
const currentTab = ref('hot'); // 'hot' 或 'new'
|
||||
const isLoggedIn = computed(() => !!userStore.token || !!userStore.userInfo?.nickName);
|
||||
const commentLoading = ref(false);
|
||||
const isSendingComment = ref(false);
|
||||
const commentError = ref('');
|
||||
const commentLoadText = computed(() => {
|
||||
if (commentLoading.value && comments.value.length) return '加载中...';
|
||||
if (!hasMore.value) return '没有更多了';
|
||||
return '上拉加载更多';
|
||||
});
|
||||
|
||||
const goBack = () => {
|
||||
uni.navigateBack();
|
||||
@@ -215,9 +239,10 @@ const handleSendComment = async (payload) => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!detailData.value.topicId || !itemId.value) return;
|
||||
if (!detailData.value.topicId || !itemId.value || isSendingComment.value) return;
|
||||
|
||||
try {
|
||||
isSendingComment.value = true;
|
||||
uni.showLoading({ title: '发送中...' });
|
||||
await topicItemComment({
|
||||
topicId: detailData.value.topicId,
|
||||
@@ -237,7 +262,6 @@ const handleSendComment = async (payload) => {
|
||||
// 刷新页面数据以获取最新评论
|
||||
currentPage.value = 1;
|
||||
hasMore.value = true;
|
||||
comments.value = [];
|
||||
uni.$trackRecord({
|
||||
eventName: 'comment',
|
||||
eventType: 'comment',
|
||||
@@ -248,13 +272,16 @@ const handleSendComment = async (payload) => {
|
||||
page: 'rating_detail'
|
||||
}
|
||||
});
|
||||
getCommentsData();
|
||||
attitudePanelRef.value?.resetComment?.();
|
||||
await getCommentsData({ replace: true });
|
||||
} catch (error) {
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: '发送失败',
|
||||
icon: 'none'
|
||||
});
|
||||
} finally {
|
||||
isSendingComment.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -263,16 +290,34 @@ const switchTab = (tab) => {
|
||||
currentTab.value = tab;
|
||||
currentPage.value = 1;
|
||||
hasMore.value = true;
|
||||
// comments.value = []; // 移除这行,避免数据清空导致高度塌陷
|
||||
getCommentsData(true); // 传入标识表示是切换榜单
|
||||
commentError.value = '';
|
||||
getCommentsData({ replace: true });
|
||||
};
|
||||
|
||||
const getCommentsData = async (isSwitchTab = false) => {
|
||||
if (!detailData.value.topicId || !itemId.value || loading.value) return;
|
||||
const resolveCommentHasMore = (res, list) => {
|
||||
const data = res?.data || res || {};
|
||||
const hasNext = data?.hasNext ?? res?.hasNext;
|
||||
if (typeof hasNext === 'boolean') return hasNext;
|
||||
|
||||
const pages = Number(data?.pages ?? res?.pages ?? 0);
|
||||
if (pages > 0) return currentPage.value < pages;
|
||||
|
||||
const total = Number(data?.total ?? res?.total ?? 0);
|
||||
if (total > 0) {
|
||||
const size = Number(data?.size ?? data?.pageSize ?? res?.size ?? res?.pageSize ?? list.length || 1);
|
||||
return currentPage.value * size < total;
|
||||
}
|
||||
|
||||
return list.length > 0;
|
||||
};
|
||||
|
||||
const getCommentsData = async ({ replace = false } = {}) => {
|
||||
if (!detailData.value.topicId || !itemId.value || commentLoading.value) return;
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
const orderBy = currentTab.value;
|
||||
commentLoading.value = true;
|
||||
commentError.value = '';
|
||||
const orderBy = currentTab.value === 'hot' ? 1 : 2;
|
||||
const res = await topicItemCommentList(detailData.value.topicId, itemId.value, currentPage.value, orderBy);
|
||||
const rawList =
|
||||
res?.data?.records ||
|
||||
@@ -297,21 +342,42 @@ const getCommentsData = async (isSwitchTab = false) => {
|
||||
userAction: item.userAction || "" // 夯/顶级/人上人/NPC/拉
|
||||
}));
|
||||
|
||||
if (currentPage.value === 1 || isSwitchTab) {
|
||||
if (currentPage.value === 1 || replace) {
|
||||
comments.value = formattedList;
|
||||
} else {
|
||||
comments.value = [...comments.value, ...formattedList];
|
||||
}
|
||||
|
||||
// 假设每页10条,如果返回的少于10条则没有更多了
|
||||
hasMore.value = list.length >= 6;
|
||||
hasMore.value = resolveCommentHasMore(res, list);
|
||||
} catch (error) {
|
||||
console.error('获取评论列表失败:', error);
|
||||
commentError.value = '请检查网络后重试';
|
||||
if (currentPage.value > 1) {
|
||||
currentPage.value -= 1;
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
commentLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const retryLoadComments = () => {
|
||||
if (!comments.value.length) {
|
||||
currentPage.value = 1;
|
||||
}
|
||||
getCommentsData({ replace: currentPage.value === 1 });
|
||||
};
|
||||
|
||||
const handleCommentLikeChange = ({ id, isLiked, likes }) => {
|
||||
comments.value = comments.value.map((item) => {
|
||||
if (item.id !== id) return item;
|
||||
return {
|
||||
...item,
|
||||
isLiked,
|
||||
likes
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const getDetailData = async () => {
|
||||
if (!itemId.value) return;
|
||||
try {
|
||||
@@ -344,7 +410,7 @@ const getDetailData = async () => {
|
||||
|
||||
// 拉取真实的评论列表
|
||||
if (currentPage.value === 1) {
|
||||
getCommentsData();
|
||||
getCommentsData({ replace: true });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取详情失败:', error);
|
||||
@@ -377,6 +443,7 @@ const handleLoginSuccess = () => {
|
||||
currentPage.value = 1;
|
||||
hasMore.value = true;
|
||||
comments.value = [];
|
||||
commentError.value = '';
|
||||
getDetailData();
|
||||
};
|
||||
|
||||
@@ -405,11 +472,12 @@ onPullDownRefresh(() => {
|
||||
currentPage.value = 1;
|
||||
hasMore.value = true;
|
||||
comments.value = [];
|
||||
commentError.value = '';
|
||||
getDetailData();
|
||||
});
|
||||
|
||||
onReachBottom(() => {
|
||||
if (!hasMore.value || loading.value) return;
|
||||
if (!hasMore.value || commentLoading.value) return;
|
||||
currentPage.value += 1;
|
||||
getCommentsData();
|
||||
});
|
||||
@@ -749,6 +817,47 @@ onReachBottom(() => {
|
||||
.comment-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 400rpx;
|
||||
}
|
||||
|
||||
.comment-state {
|
||||
min-height: 400rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
padding: 40rpx 32rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.comment-state-title {
|
||||
font-size: 30rpx;
|
||||
color: #222;
|
||||
font-weight: 700;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.comment-state-desc {
|
||||
font-size: 24rpx;
|
||||
color: #9aa0ae;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.comment-state-btn {
|
||||
margin-top: 24rpx;
|
||||
height: 72rpx;
|
||||
line-height: 72rpx;
|
||||
padding: 0 32rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #4d44f1;
|
||||
color: #fff;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.comment-state-btn::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.load-more {
|
||||
|
||||
Reference in New Issue
Block a user