Compare commits
5 Commits
7a332ba44d
...
feat/info-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4fb8a05f8d | ||
|
|
8d2337e5b7 | ||
|
|
d14084c2a1 | ||
|
|
d1d4481ff5 | ||
|
|
a47b0e2a7a |
@@ -1,5 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="comment-item">
|
<view
|
||||||
|
class="comment-item"
|
||||||
|
:id="`comment-${localComment.id}`"
|
||||||
|
:class="{ 'comment-item--anchored': localComment.id === props.activeAnchorId }"
|
||||||
|
>
|
||||||
<image class="c-avatar" :src="localComment.avatar" mode="aspectFill" />
|
<image class="c-avatar" :src="localComment.avatar" mode="aspectFill" />
|
||||||
<view class="c-content-wrap">
|
<view class="c-content-wrap">
|
||||||
<view class="c-header">
|
<view class="c-header">
|
||||||
@@ -45,6 +49,8 @@
|
|||||||
v-for="reply in localComment.replies"
|
v-for="reply in localComment.replies"
|
||||||
:key="reply.id"
|
:key="reply.id"
|
||||||
class="reply-item"
|
class="reply-item"
|
||||||
|
:id="`reply-${reply.id}`"
|
||||||
|
:class="{ 'reply-item--anchored': reply.id === props.activeAnchorId }"
|
||||||
>
|
>
|
||||||
<image class="reply-avatar" :src="reply.avatar" mode="aspectFill" />
|
<image class="reply-avatar" :src="reply.avatar" mode="aspectFill" />
|
||||||
<view class="reply-main">
|
<view class="reply-main">
|
||||||
@@ -104,6 +110,10 @@ const props = defineProps({
|
|||||||
pageName: {
|
pageName: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'rating_detail'
|
default: 'rating_detail'
|
||||||
|
},
|
||||||
|
activeAnchorId: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -256,13 +266,21 @@ const handleLike = async (target = null) => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
padding: 32rpx 0;
|
padding: 32rpx 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: background-color 0.2s;
|
transition: background-color 0.2s, transform 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-item:active {
|
.comment-item:active {
|
||||||
background-color: #fafbfe;
|
background-color: #fafbfe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comment-item--anchored {
|
||||||
|
margin: 0 -16rpx;
|
||||||
|
padding: 32rpx 16rpx;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
background: linear-gradient(135deg, rgba(92, 67, 245, 0.1), rgba(92, 67, 245, 0.04));
|
||||||
|
transform: translateY(-2rpx);
|
||||||
|
}
|
||||||
|
|
||||||
.comment-item::after {
|
.comment-item::after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -427,6 +445,13 @@ const handleLike = async (target = null) => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 16rpx;
|
gap: 16rpx;
|
||||||
padding-bottom: 18rpx;
|
padding-bottom: 18rpx;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
transition: background-color 0.2s, padding 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-item--anchored {
|
||||||
|
padding: 16rpx 14rpx 18rpx;
|
||||||
|
background: rgba(92, 67, 245, 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
.reply-avatar {
|
.reply-avatar {
|
||||||
|
|||||||
@@ -79,6 +79,7 @@
|
|||||||
:comment="comment"
|
:comment="comment"
|
||||||
:like-handler="likeHandler"
|
:like-handler="likeHandler"
|
||||||
:page-name="pageName"
|
:page-name="pageName"
|
||||||
|
:active-anchor-id="activeAnchorId"
|
||||||
@need-login="emitNeedLogin"
|
@need-login="emitNeedLogin"
|
||||||
@like-change="handleCommentLikeChange"
|
@like-change="handleCommentLikeChange"
|
||||||
@reply="openReplyPopup"
|
@reply="openReplyPopup"
|
||||||
@@ -331,8 +332,10 @@ const replyPopupVisible = ref(false);
|
|||||||
const replyInputFocus = ref(false);
|
const replyInputFocus = ref(false);
|
||||||
const replyContent = ref("");
|
const replyContent = ref("");
|
||||||
const replyKeyboardHeight = ref(0);
|
const replyKeyboardHeight = ref(0);
|
||||||
|
const activeAnchorId = ref("");
|
||||||
|
|
||||||
let keyboardHeightListener = null;
|
let keyboardHeightListener = null;
|
||||||
|
let anchorHighlightTimer = null;
|
||||||
|
|
||||||
const isLoggedIn = computed(() => !!userStore.token || !!userStore.userInfo?.nickName);
|
const isLoggedIn = computed(() => !!userStore.token || !!userStore.userInfo?.nickName);
|
||||||
const replyPlaceholder = computed(() => {
|
const replyPlaceholder = computed(() => {
|
||||||
@@ -433,6 +436,98 @@ const loadMoreComments = async () => {
|
|||||||
await loadComments();
|
await loadComments();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getCommentById = (commentId) => {
|
||||||
|
return comments.value.find((item) => item.id === commentId) || null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getLoadedAnchorTarget = (targetCommentId) => {
|
||||||
|
for (const comment of comments.value) {
|
||||||
|
if (String(comment.id) === String(targetCommentId)) {
|
||||||
|
return { type: "comment", id: comment.id };
|
||||||
|
}
|
||||||
|
const reply = (comment.replies || []).find((item) => String(item.id) === String(targetCommentId));
|
||||||
|
if (reply) {
|
||||||
|
return { type: "reply", id: reply.id, parentId: comment.id };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const markAnchorActive = (targetCommentId) => {
|
||||||
|
if (!targetCommentId) return;
|
||||||
|
activeAnchorId.value = String(targetCommentId);
|
||||||
|
if (anchorHighlightTimer) {
|
||||||
|
clearTimeout(anchorHighlightTimer);
|
||||||
|
}
|
||||||
|
anchorHighlightTimer = setTimeout(() => {
|
||||||
|
activeAnchorId.value = "";
|
||||||
|
anchorHighlightTimer = null;
|
||||||
|
}, 2200);
|
||||||
|
};
|
||||||
|
|
||||||
|
const scrollToAnchorNode = async (target) => {
|
||||||
|
if (!target?.id) return false;
|
||||||
|
markAnchorActive(target.id);
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
return await new Promise((resolve) => {
|
||||||
|
uni.pageScrollTo({
|
||||||
|
selector: `#${target.type === "reply" ? "reply" : "comment"}-${target.id}`,
|
||||||
|
offsetTop: 108,
|
||||||
|
duration: 300,
|
||||||
|
success: () => resolve(true),
|
||||||
|
fail: () => resolve(false),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const ensureRepliesContainTarget = async (commentId, targetCommentId) => {
|
||||||
|
let currentComment = getCommentById(commentId);
|
||||||
|
if (!currentComment?.replyCount) return null;
|
||||||
|
|
||||||
|
if (!currentComment.repliesLoaded) {
|
||||||
|
await loadReplies(currentComment, 1);
|
||||||
|
currentComment = getCommentById(commentId);
|
||||||
|
const loadedTarget = getLoadedAnchorTarget(targetCommentId);
|
||||||
|
if (loadedTarget) return loadedTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (currentComment?.repliesHasMore) {
|
||||||
|
await loadReplies(currentComment, Number(currentComment.repliesPage || 1) + 1);
|
||||||
|
currentComment = getCommentById(commentId);
|
||||||
|
const loadedTarget = getLoadedAnchorTarget(targetCommentId);
|
||||||
|
if (loadedTarget) return loadedTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getLoadedAnchorTarget(targetCommentId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const scrollToComment = async (targetCommentId) => {
|
||||||
|
if (!targetCommentId || !props.requestKey || !props.visible) return false;
|
||||||
|
|
||||||
|
let matchedTarget = getLoadedAnchorTarget(targetCommentId);
|
||||||
|
if (matchedTarget) {
|
||||||
|
return await scrollToAnchorNode(matchedTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (hasMore.value) {
|
||||||
|
await loadMoreComments();
|
||||||
|
matchedTarget = getLoadedAnchorTarget(targetCommentId);
|
||||||
|
if (matchedTarget) {
|
||||||
|
return await scrollToAnchorNode(matchedTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const comment of comments.value) {
|
||||||
|
matchedTarget = await ensureRepliesContainTarget(comment.id, targetCommentId);
|
||||||
|
if (matchedTarget) {
|
||||||
|
return await scrollToAnchorNode(matchedTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
const switchTab = (tab) => {
|
const switchTab = (tab) => {
|
||||||
if (currentTab.value === tab) return;
|
if (currentTab.value === tab) return;
|
||||||
currentTab.value = tab;
|
currentTab.value = tab;
|
||||||
@@ -446,11 +541,18 @@ const submitMainComment = async () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
sending.value = true;
|
sending.value = true;
|
||||||
await props.publishHandler({
|
const res = await props.publishHandler({
|
||||||
content,
|
content,
|
||||||
mode: "comment",
|
mode: "comment",
|
||||||
replyTarget: null,
|
replyTarget: null,
|
||||||
});
|
});
|
||||||
|
if(res?.success === false) {
|
||||||
|
uni.showToast({
|
||||||
|
title: res?.message || '发布失败',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (props.showSuccessToast) {
|
if (props.showSuccessToast) {
|
||||||
uni.showToast({ title: props.mainSuccessText, icon: "none" });
|
uni.showToast({ title: props.mainSuccessText, icon: "none" });
|
||||||
}
|
}
|
||||||
@@ -493,11 +595,18 @@ const submitReplyComment = async () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
sendingReply.value = true;
|
sendingReply.value = true;
|
||||||
await props.publishHandler({
|
const res = await props.publishHandler({
|
||||||
content,
|
content,
|
||||||
mode: "reply",
|
mode: "reply",
|
||||||
replyTarget: replyTarget.value,
|
replyTarget: replyTarget.value,
|
||||||
});
|
});
|
||||||
|
if(res?.success === false) {
|
||||||
|
uni.showToast({
|
||||||
|
title: res?.message || '回复失败',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (props.showSuccessToast) {
|
if (props.showSuccessToast) {
|
||||||
uni.showToast({ title: props.replySuccessText, icon: "none" });
|
uni.showToast({ title: props.replySuccessText, icon: "none" });
|
||||||
}
|
}
|
||||||
@@ -613,11 +722,15 @@ onUnmounted(() => {
|
|||||||
if (uni.offKeyboardHeightChange && keyboardHeightListener) {
|
if (uni.offKeyboardHeightChange && keyboardHeightListener) {
|
||||||
uni.offKeyboardHeightChange(keyboardHeightListener);
|
uni.offKeyboardHeightChange(keyboardHeightListener);
|
||||||
}
|
}
|
||||||
|
if (anchorHighlightTimer) {
|
||||||
|
clearTimeout(anchorHighlightTimer);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
refreshComments,
|
refreshComments,
|
||||||
loadMoreComments,
|
loadMoreComments,
|
||||||
|
scrollToComment,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -120,12 +120,8 @@ const loadTopicList = async (categoryId, page = 1) => {
|
|||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const res = await fetchTopicList(categoryId, page);
|
const res = await fetchTopicList(categoryId, page);
|
||||||
const rawList =
|
const rawList =res?.list || [];
|
||||||
res?.data?.records ||
|
|
||||||
res?.data?.list ||
|
|
||||||
res?.records ||
|
|
||||||
res?.list ||
|
|
||||||
(Array.isArray(res?.data) ? res.data : []);
|
|
||||||
const list = Array.isArray(rawList) ? rawList : [];
|
const list = Array.isArray(rawList) ? rawList : [];
|
||||||
// 合并数据
|
// 合并数据
|
||||||
topicList.value = [...topicList.value, ...list];
|
topicList.value = [...topicList.value, ...list];
|
||||||
|
|||||||
@@ -294,9 +294,8 @@ const resolveActionText = (item) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const resolveJumpText = (item) => {
|
const resolveJumpText = (item) => {
|
||||||
if(item.title.includes("已提交审核") || item.title.includes("未通过")) return "";
|
if(item.title.includes("已提交审核") || item.title.includes("未通过") || item.title.includes("评分项")) return "";
|
||||||
|
|
||||||
if (item.itemId) return "查看评分详情";
|
|
||||||
if (item.topicId) return "查看话题";
|
if (item.topicId) return "查看话题";
|
||||||
return "查看消息";
|
return "查看消息";
|
||||||
};
|
};
|
||||||
@@ -405,9 +404,16 @@ const setItemReadState = (id, isRead = true) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleNavigate = (item) => {
|
const handleNavigate = (item) => {
|
||||||
|
const isCommentInteraction = item?.type === 'comment' || item?.type === 'comment_like';
|
||||||
|
const targetCommentId =
|
||||||
|
item?.commentId ||
|
||||||
|
(item?.targetType === 'comment' ? item?.targetId : '') ||
|
||||||
|
item?.metadata?.commentId ||
|
||||||
|
'';
|
||||||
|
|
||||||
if (item.itemId) {
|
if (item.itemId) {
|
||||||
uni.navigateTo({
|
uni.navigateTo({
|
||||||
url: `/pages/rating/detail?topicId=${item.topicId || ""}&itemId=${item.itemId}`,
|
url: `/pages/rating/detail?topicId=${item.topicId || ""}&itemId=${item.itemId}${isCommentInteraction && targetCommentId ? `&commentId=${targetCommentId}` : ""}`,
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -438,7 +444,7 @@ const markSingleAsRead = async (item) => {
|
|||||||
|
|
||||||
const handleItemTap = async (item) => {
|
const handleItemTap = async (item) => {
|
||||||
await markSingleAsRead(item);
|
await markSingleAsRead(item);
|
||||||
if(item.title.includes("未通过") || item.title.includes("已提交审核")) return
|
if(item.title.includes("未通过") || item.title.includes("已提交审核") || item.title.includes("评分项")) return
|
||||||
handleNavigate(item);
|
handleNavigate(item);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,12 @@
|
|||||||
<view class="tags-container" v-else-if="!isLoggedIn">
|
<view class="tags-container" v-else-if="!isLoggedIn">
|
||||||
<text class="tags-text">点击登录解锁更多功能</text>
|
<text class="tags-text">点击登录解锁更多功能</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<view v-if="isLoggedIn && userStats.joinedDay > 0" class="joined-day-pill">
|
||||||
|
<text class="joined-day-label">已加入</text>
|
||||||
|
<text class="joined-day-value">{{ userStats.joinedDay }}</text>
|
||||||
|
<text class="joined-day-label">天</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
<view class="stats-container">
|
<view class="stats-container">
|
||||||
<view class="stat-item">
|
<view class="stat-item">
|
||||||
@@ -40,8 +46,8 @@
|
|||||||
</view>
|
</view>
|
||||||
<view class="stat-divider"></view>
|
<view class="stat-divider"></view>
|
||||||
<view class="stat-item">
|
<view class="stat-item">
|
||||||
<text class="stat-num">{{ isLoggedIn ? userStats.comment : '-' }}</text>
|
<text class="stat-num">{{ isLoggedIn ? userStats.pkCount : '-' }}</text>
|
||||||
<text class="stat-label">评论数</text>
|
<text class="stat-label">参与PK</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="stat-divider"></view>
|
<view class="stat-divider"></view>
|
||||||
<view class="stat-item">
|
<view class="stat-item">
|
||||||
@@ -71,13 +77,13 @@
|
|||||||
<view class="menu-item" @tap="navTo('/pages/mine/pk')">
|
<view class="menu-item" @tap="navTo('/pages/mine/pk')">
|
||||||
<view class="icon-left"><text class="icon-bookmark"></text></view>
|
<view class="icon-left"><text class="icon-bookmark"></text></view>
|
||||||
<text class="menu-text">我参与的PK</text>
|
<text class="menu-text">我参与的PK</text>
|
||||||
<text class="menu-value" v-if="isLoggedIn">{{ userStats.participant }}</text>
|
<text class="menu-value" v-if="isLoggedIn">{{ userStats.pkCount }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="menu-item" @tap="navTo('comments')">
|
<!-- <view class="menu-item" @tap="navTo('comments')">
|
||||||
<view class="icon-left"><text class="icon-document"></text></view>
|
<view class="icon-left"><text class="icon-document"></text></view>
|
||||||
<text class="menu-text">我的评论</text>
|
<text class="menu-text">我的评论</text>
|
||||||
<text class="menu-value" v-if="isLoggedIn">{{ userStats.comment }}</text>
|
<text class="menu-value" v-if="isLoggedIn">{{ userStats.comment }}</text>
|
||||||
</view>
|
</view> -->
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- Menu Group 2 -->
|
<!-- Menu Group 2 -->
|
||||||
@@ -130,6 +136,8 @@ const userStats = ref({
|
|||||||
participant: 0,
|
participant: 0,
|
||||||
comment: 0,
|
comment: 0,
|
||||||
liked: 0,
|
liked: 0,
|
||||||
|
pkCount: 0,
|
||||||
|
joinedDay: 0,
|
||||||
label: []
|
label: []
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -139,6 +147,8 @@ const loadUserStats = async () => {
|
|||||||
participant: 0,
|
participant: 0,
|
||||||
comment: 0,
|
comment: 0,
|
||||||
liked: 0,
|
liked: 0,
|
||||||
|
pkCount: 0,
|
||||||
|
joinedDay: 0,
|
||||||
label: []
|
label: []
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
@@ -150,6 +160,8 @@ const loadUserStats = async () => {
|
|||||||
participant: data.participant || 0,
|
participant: data.participant || 0,
|
||||||
comment: data.comment || 0,
|
comment: data.comment || 0,
|
||||||
liked: data.liked || 0,
|
liked: data.liked || 0,
|
||||||
|
pkCount: data.pkCount || 0,
|
||||||
|
joinedDay: data.joinedDay || 0,
|
||||||
label: data.label || []
|
label: data.label || []
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -312,7 +324,7 @@ const navTo = (page) => {
|
|||||||
.tags-container {
|
.tags-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 48rpx;
|
margin-bottom: 24rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sparkle-icon {
|
.sparkle-icon {
|
||||||
@@ -326,6 +338,31 @@ const navTo = (page) => {
|
|||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.joined-day-pill {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8rpx;
|
||||||
|
height: 52rpx;
|
||||||
|
padding: 0 20rpx;
|
||||||
|
margin-bottom: 36rpx;
|
||||||
|
border-radius: 999rpx;
|
||||||
|
background: linear-gradient(135deg, rgba(91, 84, 223, 0.12), rgba(69, 59, 199, 0.05));
|
||||||
|
box-shadow: inset 0 0 0 2rpx rgba(91, 84, 223, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.joined-day-label {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #7b8191;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.joined-day-value {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #453bc7;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
.stats-container {
|
.stats-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
v-for="(item, index) in topics"
|
v-for="(item, index) in topics"
|
||||||
:key="item.id || index"
|
:key="item.id || index"
|
||||||
:topic="item"
|
:topic="item"
|
||||||
@card-click="goToTopicDetail(item.id)"
|
@item-click="goToTopicDetail(item.id)"
|
||||||
/>
|
/>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -83,15 +83,15 @@ const loadData = async (page = 1) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 构造适合 TopicCard 渲染的数据格式
|
// 构造适合 TopicCard 渲染的数据格式
|
||||||
const formattedList = list.map(item => ({
|
// const formattedList = list.map(item => ({
|
||||||
id: item.topicId || item.id,
|
// id: item.topicId || item.id,
|
||||||
title: item.topicName || item.title || '未知话题',
|
// title: item.topicName || item.title || '未知话题',
|
||||||
image: item.image || item.coverUrl || 'https://api.dicebear.com/7.x/shapes/svg?seed=' + (item.topicId || item.id), // 给个默认图防止报错
|
// image: item.image || item.coverUrl || 'https://api.dicebear.com/7.x/shapes/svg?seed=' + (item.topicId || item.id), // 给个默认图防止报错
|
||||||
views: item.participantCount || item.views || 0,
|
// views: item.participantCount || item.views || 0,
|
||||||
items: item.items || item.ratingItems || []
|
// items: item.items || item.ratingItems || []
|
||||||
}));
|
// }));
|
||||||
|
|
||||||
topics.value = [...topics.value, ...formattedList];
|
topics.value = [...topics.value, ...list];
|
||||||
|
|
||||||
// 判断是否有下一页
|
// 判断是否有下一页
|
||||||
hasMore.value = list.length >= pageSize;
|
hasMore.value = list.length >= pageSize;
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ const commentSectionRef = ref(null);
|
|||||||
const isLoggedIn = computed(() => !!userStore.token || !!userStore.userInfo?.nickName);
|
const isLoggedIn = computed(() => !!userStore.token || !!userStore.userInfo?.nickName);
|
||||||
const isSendingComment = ref(false);
|
const isSendingComment = ref(false);
|
||||||
const pkPreview = ref(null);
|
const pkPreview = ref(null);
|
||||||
|
const pendingAnchorCommentId = ref('');
|
||||||
const commentRequestKey = computed(() => {
|
const commentRequestKey = computed(() => {
|
||||||
if (!detailData.value.topicId || !itemId.value) return '';
|
if (!detailData.value.topicId || !itemId.value) return '';
|
||||||
return `${detailData.value.topicId}_${itemId.value}`;
|
return `${detailData.value.topicId}_${itemId.value}`;
|
||||||
@@ -360,6 +361,14 @@ const handleCommentPublished = ({ mode, content, replyTarget }) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const scrollToPendingComment = async () => {
|
||||||
|
if (!pendingAnchorCommentId.value) return;
|
||||||
|
const found = await commentSectionRef.value?.scrollToComment?.(pendingAnchorCommentId.value);
|
||||||
|
if (found) {
|
||||||
|
pendingAnchorCommentId.value = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleSendComment = async (payload) => {
|
const handleSendComment = async (payload) => {
|
||||||
if (!isLoggedIn.value) {
|
if (!isLoggedIn.value) {
|
||||||
openLoginPopup();
|
openLoginPopup();
|
||||||
@@ -371,13 +380,19 @@ const handleSendComment = async (payload) => {
|
|||||||
try {
|
try {
|
||||||
isSendingComment.value = true;
|
isSendingComment.value = true;
|
||||||
uni.showLoading({ title: '发送中...' });
|
uni.showLoading({ title: '发送中...' });
|
||||||
await publishTopicComment({
|
const res = await publishTopicComment({
|
||||||
content: payload.content,
|
content: payload.content,
|
||||||
mode: 'comment',
|
mode: 'comment',
|
||||||
replyTarget: null
|
replyTarget: null
|
||||||
});
|
});
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
|
if(res?.success === false) {
|
||||||
|
uni.showToast({
|
||||||
|
title: res?.message || '发送失败',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
handleCommentPublished({
|
handleCommentPublished({
|
||||||
mode: 'comment',
|
mode: 'comment',
|
||||||
content: payload.content,
|
content: payload.content,
|
||||||
@@ -418,6 +433,7 @@ const getDetailData = async () => {
|
|||||||
currentAction.value = data.userAction || '';
|
currentAction.value = data.userAction || '';
|
||||||
|
|
||||||
await commentSectionRef.value?.refreshComments?.();
|
await commentSectionRef.value?.refreshComments?.();
|
||||||
|
await scrollToPendingComment();
|
||||||
getPkPreviewData();
|
getPkPreviewData();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取详情失败:', error);
|
console.error('获取详情失败:', error);
|
||||||
@@ -440,6 +456,9 @@ onLoad((options) => {
|
|||||||
if (options.topicId) {
|
if (options.topicId) {
|
||||||
detailData.value.topicId = options.topicId;
|
detailData.value.topicId = options.topicId;
|
||||||
}
|
}
|
||||||
|
if (options.commentId) {
|
||||||
|
pendingAnchorCommentId.value = options.commentId;
|
||||||
|
}
|
||||||
if (options.itemId) {
|
if (options.itemId) {
|
||||||
itemId.value = options.itemId;
|
itemId.value = options.itemId;
|
||||||
getDetailData();
|
getDetailData();
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
<text class="ai-content">{{ topicData.aiSummary }}</text>
|
<text class="ai-content">{{ topicData.aiSummary }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view v-if="pkPair.left && pkPair.right" class="pk-entry-card" @tap="goToPk()">
|
<!-- <view v-if="pkPair.left && pkPair.right" class="pk-entry-card" @tap="goToPk()">
|
||||||
<view class="pk-entry-header">
|
<view class="pk-entry-header">
|
||||||
<view class="pk-entry-title-wrap">
|
<view class="pk-entry-title-wrap">
|
||||||
<text class="pk-entry-title">PK 对决模式</text>
|
<text class="pk-entry-title">PK 对决模式</text>
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
<text class="pk-entry-name">{{ pkPair.right.name }}</text>
|
<text class="pk-entry-name">{{ pkPair.right.name }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view> -->
|
||||||
|
|
||||||
<!-- 领奖台 (Top 3) -->
|
<!-- 领奖台 (Top 3) -->
|
||||||
<view class="podium-section" v-if="ratingItems && ratingItems.length >= 3">
|
<view class="podium-section" v-if="ratingItems && ratingItems.length >= 3">
|
||||||
|
|||||||
Reference in New Issue
Block a user