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