2026-07-07 17:51:33 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<view class="recursive-comment">
|
|
|
|
|
|
<view
|
|
|
|
|
|
class="comment-item"
|
|
|
|
|
|
:class="{ 'nested': level > 0 }"
|
|
|
|
|
|
:style="{ paddingLeft: level > 0 ? '80rpx' : '0' }"
|
|
|
|
|
|
>
|
|
|
|
|
|
<image class="c-avatar" :src="item.userImage" mode="aspectFill"></image>
|
|
|
|
|
|
<view class="c-body">
|
|
|
|
|
|
<view class="c-user-line">
|
|
|
|
|
|
<text class="c-nickname">{{ item.userName }}</text>
|
|
|
|
|
|
<text class="c-author" v-if="item.author === 1">作者</text>
|
|
|
|
|
|
<text class="c-vip" v-if="item.vipLevel">88VIP</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="c-text">
|
|
|
|
|
|
{{level === 0 ? '' : '回复'}}<text class="c-reply-at" v-if="parentName">@{{ parentName }}:</text>
|
|
|
|
|
|
<text>{{ item.content }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<view class="c-footer">
|
|
|
|
|
|
<text class="c-time">{{ formatDate(item.ctdate) }}</text>
|
|
|
|
|
|
<text class="c-reply-btn" @tap="handleReply">回复</text>
|
|
|
|
|
|
<text class="c-reply-btn" style="margin-left:20rpx" @tap="handleDelete" v-if="item.userId === userId">删除</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 递归渲染子评论 -->
|
|
|
|
|
|
<template v-if="item.children && item.children.length > 0">
|
|
|
|
|
|
<RecursiveComment
|
|
|
|
|
|
v-for="(child, index) in item.children"
|
|
|
|
|
|
:key="index"
|
|
|
|
|
|
:item="child"
|
|
|
|
|
|
:userId="userId"
|
|
|
|
|
|
:parentName="item.userName"
|
|
|
|
|
|
:level="level + 1"
|
|
|
|
|
|
@reply="(childItem, parent) => $emit('reply', childItem, parent || item)"
|
2026-07-09 16:51:12 +08:00
|
|
|
|
@deleteSuccess="(item) => $emit('deleteSuccess', item)"
|
2026-07-07 17:51:33 +08:00
|
|
|
|
/>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import { deleteReview } from '@/api/product.js';
|
|
|
|
|
|
import { formatDate } from '@/utils/index.js';
|
|
|
|
|
|
export default {
|
|
|
|
|
|
name: 'RecursiveComment',
|
|
|
|
|
|
props: {
|
|
|
|
|
|
item: {
|
|
|
|
|
|
type: Object,
|
|
|
|
|
|
required: true
|
|
|
|
|
|
},
|
|
|
|
|
|
userId: {
|
|
|
|
|
|
type: String,
|
|
|
|
|
|
default: ''
|
|
|
|
|
|
},
|
|
|
|
|
|
parentName: {
|
|
|
|
|
|
type: String,
|
|
|
|
|
|
default: ''
|
|
|
|
|
|
},
|
|
|
|
|
|
level: {
|
|
|
|
|
|
type: Number,
|
|
|
|
|
|
default: 0
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
|
|
|
|
|
formatDate,
|
|
|
|
|
|
handleReply() {
|
|
|
|
|
|
this.$emit('reply', this.item, this.parentName ? null : this.item);
|
|
|
|
|
|
},
|
|
|
|
|
|
async handleDelete() {
|
|
|
|
|
|
console.log('删除',this.item);
|
|
|
|
|
|
const res = await uni.showModal({
|
|
|
|
|
|
title: '提示',
|
|
|
|
|
|
content: '确认删除吗?',
|
|
|
|
|
|
confirmColor: '#ff6b6b'
|
|
|
|
|
|
});
|
|
|
|
|
|
if (res.confirm) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
await deleteReview({ Id: this.item.id });
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '删除成功',
|
|
|
|
|
|
icon: 'success'
|
|
|
|
|
|
});
|
|
|
|
|
|
this.$emit('deleteSuccess', this.item);
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
uni.showToast({
|
|
|
|
|
|
title: '删除失败',
|
|
|
|
|
|
icon: 'none'
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.recursive-comment {
|
|
|
|
|
|
.comment-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
padding: 20rpx 0 8rpx ;
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
|
|
|
|
&.nested {
|
|
|
|
|
|
margin-left: 16rpx;
|
|
|
|
|
|
padding-left: 60rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.c-avatar {
|
|
|
|
|
|
width: 48rpx;
|
|
|
|
|
|
height: 48rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.c-body {
|
|
|
|
|
|
.c-user-line .c-nickname {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.c-text {
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.c-footer {
|
|
|
|
|
|
font-size: 22rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.c-avatar {
|
|
|
|
|
|
width: 64rpx;
|
|
|
|
|
|
height: 64rpx;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
margin-right: 16rpx;
|
|
|
|
|
|
background-color: #f0f0f0;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.c-body {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
|
|
|
|
|
|
.c-user-line {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin-bottom: 8rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.c-nickname {
|
|
|
|
|
|
font-size: 26rpx;
|
|
|
|
|
|
color: #888888;
|
|
|
|
|
|
margin-right: 10rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.c-author {
|
|
|
|
|
|
font-size: 20rpx;
|
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
|
background-color: #ff6b6b;
|
|
|
|
|
|
padding: 2rpx 8rpx;
|
|
|
|
|
|
border-radius: 4rpx;
|
|
|
|
|
|
margin-right: 8rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.c-vip {
|
|
|
|
|
|
font-size: 20rpx;
|
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
|
background: linear-gradient(135deg, #ff6b6b, #ffa940);
|
|
|
|
|
|
padding: 2rpx 8rpx;
|
|
|
|
|
|
border-radius: 4rpx;
|
|
|
|
|
|
margin-right: 8rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.c-text {
|
|
|
|
|
|
font-size: 28rpx;
|
|
|
|
|
|
color: #262626;
|
|
|
|
|
|
line-height: 1.4;
|
|
|
|
|
|
margin-bottom: 12rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.c-reply-at {
|
|
|
|
|
|
color: #7b3ff7;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.c-footer {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #aaaaaa;
|
|
|
|
|
|
|
|
|
|
|
|
.c-time {
|
|
|
|
|
|
margin-right: 20rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.c-reply-btn {
|
|
|
|
|
|
color: #555555;
|
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|