Files
frontend-app/pages/other_package/productInfo/RecursiveComment.vue
T

200 lines
4.5 KiB
Vue
Raw Normal View History

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>