addapi
This commit is contained in:
@@ -1,129 +1,131 @@
|
||||
<template>
|
||||
<!-- 评论区域 -->
|
||||
<view v-if="comments" class="comment">
|
||||
<!-- 评论头部信息 -->
|
||||
<view class="commenthead">
|
||||
<text class="commentcount">{{ totalCommentCount }}条评论</text>
|
||||
<view class="headswitch">
|
||||
<text class="inact" @tap="handleOpenApp">默认</text>
|
||||
<view class="act" @tap="handleOpenApp">最新</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 评论主体 -->
|
||||
<view v-for="commentItem in highlightedList" :key="commentItem.id" class="commentdetail" @tap="onDelegateTap">
|
||||
<!-- 头像 -->
|
||||
<view class="commentdetailleft">
|
||||
<image src="/static/logo.png" mode="aspectFill" alt="用户头像"></image>
|
||||
</view>
|
||||
|
||||
<!-- 右侧主评论 + 子评论 + 展开条 -->
|
||||
<view class="commentdetailright">
|
||||
<!-- 父评论 -->
|
||||
<view class="maincomment">
|
||||
<view class="commentdetailcontent">
|
||||
<text class="commentusername">{{ commentItem.userName }}</text>
|
||||
<rich-text class="commentusercontent" :nodes="commentItem.renderNodes" />
|
||||
<view class="date-reply">
|
||||
<uni-dateformat :date="Date.parse(commentItem.date.replace(/-/g, '/'))" :threshold="[0, 0]"
|
||||
format="yyyy-MM-dd" class="date-text" />
|
||||
<text class="replytext" @tap.stop="handleOpenApp">回复</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="spacerview"></view>
|
||||
<view class="commentlike">
|
||||
<uni-icons type="heart" size="16" color="#999" @tap.stop="handleOpenApp"></uni-icons>
|
||||
<text class="commentlikecount">{{ formatCount(commentItem.likeCount) }}</text>
|
||||
</view>
|
||||
<view class="comment">
|
||||
<main>
|
||||
<!-- 评论头部信息 -->
|
||||
<view class="commenthead">
|
||||
<text class="commentcount">{{ comments.length }}条评论</text>
|
||||
<view class="headswitch">
|
||||
<text class="inact" @tap="handleOpenApp">默认</text>
|
||||
<view class="act" @tap="handleOpenApp">最新</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 子评论列表(仅展开时显示) -->
|
||||
<view v-if="commentItem.showChild" class="commentchildcontainer">
|
||||
<view v-for="child in commentItem.children" :key="child.id" class="commentchild">
|
||||
<view class="commentchildleft">
|
||||
<image src="/static/logo.png" mode="aspectFill" alt="用户头像"></image>
|
||||
</view>
|
||||
<view class="commentchildright">
|
||||
<text class="commentusername">{{ child.userName }}</text>
|
||||
<rich-text class="commentusercontent" :nodes="child.renderNodes" />
|
||||
<view class="date-reply">
|
||||
<uni-dateformat :date="Date.parse(child.date.replace(/-/g, '/'))" :threshold="[0, 0]"
|
||||
format="yyyy-MM-dd" class="date-text" />
|
||||
<text class="replytext" @tap.stop="handleOpenApp">回复</text>
|
||||
<!-- 评论主体 -->
|
||||
|
||||
<view v-if="comments.list.length > 0">
|
||||
|
||||
<view v-for="commentItem in comments.list" :key="commentItem.id" class="commentdetail" @tap="onDelegateTap">
|
||||
<!-- 头像 -->
|
||||
<view class="commentdetailleft">
|
||||
<image :src="commentItem.userAvatar" mode="aspectFill" alt="用户头像"></image>
|
||||
</view>
|
||||
|
||||
<!-- 右侧主评论 + 子评论 + 展开条 -->
|
||||
<view class="commentdetailright">
|
||||
<!-- 父评论 -->
|
||||
<view class="maincomment">
|
||||
<view class="commentdetailcontent">
|
||||
<text class="commentusername">{{ commentItem.userName }}</text>
|
||||
<rich-text class="commentusercontent" :nodes="commentItem.renderNodes" />
|
||||
<view class="date-reply">
|
||||
<uni-dateformat v-if="commentItem.createdAt"
|
||||
:date="Date.parse(commentItem.createdAt.replace(/-/g, '/'))" :threshold="[0, 0]" format="yyyy-MM-dd"
|
||||
class="date-text" />
|
||||
<text v-else class="date-text">未知时间</text>
|
||||
<text class="replytext" @tap.stop="handleOpenApp">回复</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="spacerview"></view>
|
||||
<view class="commentlike">
|
||||
<uni-icons type="heart" size="16" color="#999" @tap.stop="handleOpenApp"></uni-icons>
|
||||
<text class="commentlikecount">{{ formatCount(commentItem.likeCount) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="commentlike">
|
||||
<uni-icons type="heart" size="16" color="#999" @tap.stop="handleOpenApp"></uni-icons>
|
||||
<text class="commentlikecount">{{ formatCount(child.likeCount) }}</text>
|
||||
|
||||
<!-- 子评论列表(仅展开时显示) -->
|
||||
<view v-if="commentItem.showChild" class="commentchildcontainer">
|
||||
<view v-for="child in commentItem.children" :key="child.id" class="commentchild">
|
||||
<view class="commentchildleft">
|
||||
<image :src="child.userAvatar || '/static/logo.png'" mode="aspectFill" alt="用户头像"></image>
|
||||
</view>
|
||||
<view class="commentchildright">
|
||||
<text class="commentusername">{{ child.userName }}</text>
|
||||
<rich-text class="commentusercontent" :nodes="child.renderNodes" />
|
||||
<view class="date-reply">
|
||||
<uni-dateformat v-if="child.date" :date="Date.parse(child.date.replace(/-/g, '/'))"
|
||||
:threshold="[0, 0]" format="yyyy-MM-dd" class="date-text" />
|
||||
<text v-else class="date-text">未知时间</text>
|
||||
<text class="replytext" @tap.stop="handleOpenApp">回复</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="commentlike">
|
||||
<uni-icons type="heart" size="16" color="#999" @tap.stop="handleOpenApp"></uni-icons>
|
||||
<text class="commentlikecount">{{ formatCount(child.likeCount) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 展开/收起按钮 -->
|
||||
<view v-if="commentItem.reply.length" class="expandcomment">
|
||||
<view style="width:20px;height:1px;background:rgba(65,60,67,.2)"></view>
|
||||
<text class="expandcommenttext" :data-cid="commentItem.id">
|
||||
{{ commentItem.showChild ? '收起' : `展开${commentItem.reply.length}条回复` }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
<!-- 展开/收起按钮 -->
|
||||
<view v-if="commentItem.children.length" class="expandcomment">
|
||||
<view style="width:20px;height:1px;background:rgba(65,60,67,.2)"></view>
|
||||
<text class="expandcommenttext" :data-cid="commentItem.id">
|
||||
{{ commentItem.showChild ? '收起' : `展开${commentItem.children.length}条回复` }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<view v-else class="nocomments">
|
||||
<image src="/static/imgs/nocomments/nocomments@3x.webp" mode="aspectFit" alt="暂无评论"></image>
|
||||
<text class="nocommentstext">空空如也~</text>
|
||||
</view>
|
||||
|
||||
<!-- 占位视图 -->
|
||||
<view class="spacerview"></view>
|
||||
</main>
|
||||
<!-- 互动区域 -->
|
||||
<Intereact />
|
||||
|
||||
</view>
|
||||
|
||||
<!-- 占位 -->
|
||||
<view class="spacerview"></view>
|
||||
|
||||
<!-- 互动区域 -->
|
||||
<view v-if="showInteraction" class="interaction">
|
||||
<view class="editarea" @tap="handleOpenApp">
|
||||
<image src="/static/imgs/editicon/icon@2x.webp" mode="aspectFit" class="editicon" alt="编辑标签"></image>
|
||||
<text class="edittext">快来互动吧…</text>
|
||||
</view>
|
||||
<view class="spacerview"></view>
|
||||
<view class="collection" @tap="handleOpenApp">
|
||||
<image src="@/static/imgs/staricon/icon@3x.webp" mode="aspectFit" class="collectionicon" alt="收藏标签"></image>
|
||||
<text class="collectioncount">{{ formatCount(collectsum) }}</text>
|
||||
</view>
|
||||
<view class="spacerview"></view>
|
||||
<view class="like" @tap="handleOpenApp">
|
||||
<image src="@/static/imgs/likeicon/icon@3x.webp" mode="aspectFit" class="likeicon" alt="点赞标签"></image>
|
||||
<text class="likecount">{{ formatCount(likesum) }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- Findmore -->
|
||||
<Findmore />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { reactive } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { getCommentList, getUserImg } from '@/api/api.js'
|
||||
import { useCommonStore } from '@/stores/common.js'
|
||||
|
||||
const props = defineProps({
|
||||
comments: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
showInteraction: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
collectsum: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
likesum: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
})
|
||||
import Findmore from '@/pages/findmore/findmore.vue'
|
||||
import Intereact from '@/pages/intereact/intereact.vue'
|
||||
|
||||
const common = useCommonStore()
|
||||
|
||||
const comments = reactive({
|
||||
list: [],
|
||||
length: 0
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
postid: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
// 处理评论点击事件
|
||||
function onDelegateTap(e) {
|
||||
const cid = e.target?.dataset?.cid
|
||||
if (!cid || !props.comments) return
|
||||
const item = props.comments.find(v => v.id == cid)
|
||||
if (!item || !item.children || !item.children.length) return
|
||||
if (!cid || !comments.list) return
|
||||
const item = comments.list.find(v => v.id == cid)
|
||||
if (!item || !item.reply || !item.reply.length) return
|
||||
item.showChild = !item.showChild
|
||||
}
|
||||
|
||||
@@ -137,31 +139,146 @@ function formatCount(count) {
|
||||
return common.formatCount(count)
|
||||
}
|
||||
|
||||
// 处理评论数据,添加渲染节点
|
||||
const highlightedList = computed(() =>
|
||||
props.comments ? props.comments.map(c => ({
|
||||
...c,
|
||||
renderNodes: [
|
||||
...common.atUsersToNodes(c.atUsers),
|
||||
{ type: 'text', text: c.content }
|
||||
],
|
||||
children: c.children ? c.children.map(child => ({
|
||||
...child,
|
||||
renderNodes: [
|
||||
...common.atUsersToNodes(child.atUsers),
|
||||
{ type: 'text', text: child.content }
|
||||
]
|
||||
})) : []
|
||||
})) : []
|
||||
)
|
||||
onLoad(() => {
|
||||
const params = {
|
||||
postId: props.postid
|
||||
}
|
||||
getCommentList(params).then(res => {
|
||||
try {
|
||||
// 检查响应状态
|
||||
if (res.statusCode === 200 && res.data) {
|
||||
console.log(res.data)
|
||||
comments.list = res.data.list || []
|
||||
comments.length = res.data.total || 0
|
||||
|
||||
// 处理每条评论
|
||||
comments.list.forEach(comment => {
|
||||
processComment(comment)
|
||||
})
|
||||
} else {
|
||||
throw new Error(`请求失败: ${res.statusCode}`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('处理评论数据时出错:', error)
|
||||
uni.showToast({
|
||||
title: '加载评论失败',
|
||||
icon: 'error'
|
||||
})
|
||||
// 设置默认空数据
|
||||
comments.list = []
|
||||
comments.length = 0
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error('获取评论列表失败:', error)
|
||||
uni.showToast({
|
||||
title: '网络连接异常',
|
||||
icon: 'error'
|
||||
})
|
||||
// 设置默认空数据
|
||||
comments.list = []
|
||||
comments.length = 0
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* 处理单条评论数据
|
||||
* @param {Object} comment - 评论对象
|
||||
*/
|
||||
function processComment(comment) {
|
||||
// 确保comment对象有必要的属性
|
||||
if (!comment.children || comment.children.length === 0) {
|
||||
comment.showChild = false
|
||||
}
|
||||
|
||||
// 确保user对象存在
|
||||
if (!comment.user) {
|
||||
comment.user = {}
|
||||
}
|
||||
|
||||
// 设置评论基本属性
|
||||
comment.content = comment.content || ''
|
||||
comment.likeCount = comment.likeCount || 0
|
||||
comment.userName = comment.user.nickName || '匿名用户'
|
||||
comment.createdAt = comment.createdAt || comment.date || ''
|
||||
|
||||
// 生成renderNodes用于富文本渲染
|
||||
comment.renderNodes = common.contentToRenderNodes(comment.content, comment.atUsers)
|
||||
|
||||
// 处理用户头像
|
||||
handleCommentAvatar(comment)
|
||||
|
||||
// 处理子评论
|
||||
if (comment.reply && comment.reply.length > 0) {
|
||||
// 将reply赋值给children,确保模板和代码一致
|
||||
comment.children = comment.reply
|
||||
|
||||
comment.children.forEach(childComment => {
|
||||
processChildComment(childComment)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理子评论数据
|
||||
* @param {Object} childComment - 子评论对象
|
||||
*/
|
||||
function processChildComment(childComment) {
|
||||
// 确保user对象存在
|
||||
if (!childComment.user) {
|
||||
childComment.user = {}
|
||||
}
|
||||
|
||||
// 设置子评论基本属性
|
||||
childComment.content = childComment.content || ''
|
||||
childComment.likeCount = childComment.likeCount || 0
|
||||
childComment.userName = childComment.user.nickName || '匿名用户'
|
||||
childComment.date = childComment.createdAt || childComment.date || ''
|
||||
|
||||
// 处理子评论头像
|
||||
handleCommentAvatar(childComment)
|
||||
|
||||
// 为子评论生成renderNodes
|
||||
childComment.renderNodes = common.contentToRenderNodes(childComment.content, childComment.atUsers)
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理评论头像
|
||||
* @param {Object} comment - 评论对象(主评论或子评论)
|
||||
*/
|
||||
function handleCommentAvatar(comment) {
|
||||
// 如果已经有头像URL,直接使用
|
||||
if (comment.userAvatar) {
|
||||
return
|
||||
}
|
||||
|
||||
// 确保有头像路径时才请求用户信息
|
||||
const avatarPath = comment.user.avatar
|
||||
if (avatarPath) {
|
||||
getUserImg(avatarPath).then(res => {
|
||||
try {
|
||||
if (res.statusCode === 200 && res.data) {
|
||||
// 将arrayBuffer转换为base64
|
||||
const base64 = uni.arrayBufferToBase64(res.data)
|
||||
const userImgUrl = 'data:image/webp;base64,' + base64
|
||||
comment.userAvatar = userImgUrl
|
||||
} else {
|
||||
// 使用原始头像URL作为备选
|
||||
comment.userAvatar = avatarPath || ''
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('处理用户头像信息失败:', error)
|
||||
comment.userAvatar = avatarPath || ''
|
||||
}
|
||||
}).catch(error => {
|
||||
console.warn('获取用户头像失败:', error)
|
||||
comment.userAvatar = avatarPath || ''
|
||||
})
|
||||
} else {
|
||||
// 没有头像路径时使用空字符串
|
||||
comment.userAvatar = ''
|
||||
}
|
||||
}
|
||||
|
||||
// 总评论数 = 主评论条数 + 所有子评论条数
|
||||
const totalCommentCount = computed(() =>
|
||||
props.comments ? props.comments.reduce(
|
||||
(sum, c) => sum + 1 + (c.children ? c.children.length : 0),
|
||||
0
|
||||
) : 0
|
||||
)
|
||||
|
||||
</script>
|
||||
|
||||
@@ -175,11 +292,16 @@ const totalCommentCount = computed(() =>
|
||||
.comment {
|
||||
width: 100%;
|
||||
max-width: 430px;
|
||||
padding: 16px;
|
||||
height: 50vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0 auto;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.commenthead {
|
||||
@@ -354,13 +476,12 @@ const totalCommentCount = computed(() =>
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 14px 0 0;
|
||||
}
|
||||
|
||||
.commentchild {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-bottom: 8px;
|
||||
/* margin-bottom: 8px; */
|
||||
}
|
||||
|
||||
.commentchildleft {
|
||||
@@ -388,6 +509,8 @@ const totalCommentCount = computed(() =>
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
gap: 8px;
|
||||
transition: all 0.5s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.expandcommenttext {
|
||||
@@ -402,83 +525,25 @@ const totalCommentCount = computed(() =>
|
||||
color: #110c13;
|
||||
}
|
||||
|
||||
.interaction {
|
||||
width: 100%;
|
||||
max-width: 430px;
|
||||
border: solid 1px #faf9fb;
|
||||
background-color: #faf9fb;
|
||||
.nocomments {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 11.5px 16px;
|
||||
flex-direction: row;
|
||||
box-sizing: border-box;
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.editarea {
|
||||
flex: 1;
|
||||
height: 40px;
|
||||
background-color: #fff;
|
||||
border-radius: 24px;
|
||||
max-width: 100%;
|
||||
gap: 12px;
|
||||
padding: 0 20px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.editicon {
|
||||
width: 13.3px;
|
||||
height: 14.6px;
|
||||
flex-shrink: 0;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.edittext {
|
||||
flex: 1;
|
||||
flex-grow: 0;
|
||||
.nocommentstext {
|
||||
font-size: 14px;
|
||||
font-family: 'PingFangSC';
|
||||
font-weight: normal;
|
||||
font-stretch: normal;
|
||||
font-style: normal;
|
||||
line-height: 40px;
|
||||
letter-spacing: normal;
|
||||
text-align: left;
|
||||
color: #918e93;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.collection,
|
||||
.like {
|
||||
height: 40px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.collectionicon,
|
||||
.likeicon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.collectioncount,
|
||||
.likecount {
|
||||
height: 17px;
|
||||
font-family: 'SFPro';
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
font-stretch: normal;
|
||||
font-style: normal;
|
||||
line-height: normal;
|
||||
letter-spacing: normal;
|
||||
text-align: left;
|
||||
color: #000;
|
||||
text-align: center;
|
||||
color: #918e93;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user