更新:课程详情的初步代码
This commit is contained in:
406
components/comment/CommentList.vue
Normal file
406
components/comment/CommentList.vue
Normal file
@@ -0,0 +1,406 @@
|
||||
<template>
|
||||
<view class="comment-list">
|
||||
<!-- 评论列表 -->
|
||||
<view v-for="comment in comments" :key="comment.id" class="comment-item">
|
||||
<!-- 一级评论 -->
|
||||
<view class="comment-main">
|
||||
<view class="user-info">
|
||||
<image
|
||||
:src="comment.user.avatar || defaultAvatar"
|
||||
class="avatar"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
<text class="username">{{ comment.user.name }}</text>
|
||||
</view>
|
||||
|
||||
<view class="comment-content">
|
||||
<view class="content-html" v-html="comment.content"></view>
|
||||
|
||||
<!-- 图片列表 -->
|
||||
<view v-if="comment.imgList && comment.imgList.length > 0" class="image-list">
|
||||
<image
|
||||
v-for="(img, imgIndex) in comment.imgList"
|
||||
:key="imgIndex"
|
||||
:src="img"
|
||||
class="comment-image"
|
||||
mode="aspectFill"
|
||||
@click="previewImage(img, comment.imgList)"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="comment-actions">
|
||||
<text class="time">{{ comment.createTime }}</text>
|
||||
<view class="action-btns">
|
||||
<wd-button
|
||||
size="small"
|
||||
custom-class="action-btn"
|
||||
:type="comment.support ? 'primary' : 'default'"
|
||||
@click="handleLike(comment.id)"
|
||||
>
|
||||
<wd-icon name="thumb-up" />
|
||||
<text class="btn-text">{{ comment.supportCount || 0 }}</text>
|
||||
</wd-button>
|
||||
<wd-button
|
||||
size="small"
|
||||
custom-class="action-btn"
|
||||
@click="handleReply(comment)"
|
||||
>
|
||||
<wd-icon name="chat" />
|
||||
<text class="btn-text">回复</text>
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 子评论列表 -->
|
||||
<view v-if="comment.Bchildren && comment.Bchildren.length > 0" class="sub-comments">
|
||||
<view v-for="subComment in comment.Bchildren" :key="subComment.id" class="sub-comment-item">
|
||||
<view class="sub-user-info">
|
||||
<image
|
||||
:src="subComment.user.avatar || defaultAvatar"
|
||||
class="sub-avatar"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
<text class="sub-username">{{ subComment.user.name }}</text>
|
||||
</view>
|
||||
|
||||
<view class="sub-comment-content">
|
||||
<view class="content-html" v-html="subComment.content"></view>
|
||||
|
||||
<!-- 子评论图片 -->
|
||||
<view v-if="subComment.imgList && subComment.imgList.length > 0" class="image-list">
|
||||
<image
|
||||
v-for="(img, imgIndex) in subComment.imgList"
|
||||
:key="imgIndex"
|
||||
:src="img"
|
||||
class="comment-image"
|
||||
mode="aspectFill"
|
||||
@click="previewImage(img, subComment.imgList)"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="sub-comment-actions">
|
||||
<text class="time">{{ subComment.createTime }}</text>
|
||||
<view class="action-btns">
|
||||
<wd-button
|
||||
size="small"
|
||||
custom-class="action-btn"
|
||||
:type="subComment.support ? 'primary' : 'default'"
|
||||
@click="handleLike(subComment.id)"
|
||||
>
|
||||
<wd-icon name="thumb-up" />
|
||||
<text class="btn-text">{{ subComment.supportCount || 0 }}</text>
|
||||
</wd-button>
|
||||
<wd-button
|
||||
size="small"
|
||||
custom-class="action-btn"
|
||||
@click="handleReply(subComment)"
|
||||
>
|
||||
<wd-icon name="chat" />
|
||||
<text class="btn-text">回复</text>
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 查看更多回复 -->
|
||||
<view
|
||||
v-if="comment.children && comment.children.length > comment.Bchildren.length"
|
||||
class="load-more-replies"
|
||||
@click="loadMoreReplies(comment)"
|
||||
>
|
||||
<text>查看更多回复 ({{ comment.children.length - comment.Bchildren.length }})</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 加载更多 -->
|
||||
<view v-if="hasMore" class="load-more-btn">
|
||||
<wd-button
|
||||
@click="handleLoadMore"
|
||||
:loading="loading"
|
||||
block
|
||||
>
|
||||
加载更多
|
||||
</wd-button>
|
||||
</view>
|
||||
|
||||
<!-- 已加载全部 -->
|
||||
<view v-else-if="comments.length > 0" class="no-more">
|
||||
<wd-divider>已加载全部</wd-divider>
|
||||
</view>
|
||||
|
||||
<!-- 暂无评论 -->
|
||||
<view v-else-if="!loading" class="no-comments">
|
||||
<text>暂无留言数据</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import type { IComment } from '@/types/comment'
|
||||
|
||||
interface Props {
|
||||
comments: IComment[]
|
||||
loading: boolean
|
||||
hasMore: boolean
|
||||
type: 'course' | 'book'
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
like: [commentId: number]
|
||||
reply: [comment: IComment]
|
||||
loadMore: []
|
||||
}>()
|
||||
|
||||
const defaultAvatar = '/static/icon/default-avatar.png'
|
||||
|
||||
/**
|
||||
* 预览图片
|
||||
*/
|
||||
const previewImage = (current: string, urls: string[]) => {
|
||||
uni.previewImage({
|
||||
current,
|
||||
urls,
|
||||
longPressActions: {
|
||||
itemList: ['很抱歉,暂不支持保存图片到本地'],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 点赞
|
||||
*/
|
||||
const handleLike = (commentId: number) => {
|
||||
emit('like', commentId)
|
||||
}
|
||||
|
||||
/**
|
||||
* 回复
|
||||
*/
|
||||
const handleReply = (comment: IComment) => {
|
||||
emit('reply', comment)
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载更多
|
||||
*/
|
||||
const handleLoadMore = () => {
|
||||
emit('loadMore')
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载更多回复
|
||||
*/
|
||||
const loadMoreReplies = (comment: IComment) => {
|
||||
// 显示所有子评论
|
||||
comment.Bchildren = [...comment.children]
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.comment-list {
|
||||
padding: 20rpx;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.comment-item {
|
||||
margin-bottom: 30rpx;
|
||||
padding-bottom: 30rpx;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.comment-main {
|
||||
.user-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.avatar {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.username {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.comment-content {
|
||||
margin-left: 80rpx;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.content-html {
|
||||
font-size: 28rpx;
|
||||
line-height: 1.6;
|
||||
color: #666;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.image-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 20rpx;
|
||||
gap: 10rpx;
|
||||
|
||||
.comment-image {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.comment-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-left: 80rpx;
|
||||
|
||||
.time {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.action-btns {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
|
||||
.action-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
|
||||
.btn-text {
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sub-comments {
|
||||
margin-left: 80rpx;
|
||||
margin-top: 20rpx;
|
||||
padding: 20rpx;
|
||||
background-color: #f7f8f9;
|
||||
border-radius: 8rpx;
|
||||
|
||||
.sub-comment-item {
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.sub-user-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 15rpx;
|
||||
|
||||
.sub-avatar {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 15rpx;
|
||||
}
|
||||
|
||||
.sub-username {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.sub-comment-content {
|
||||
margin-left: 55rpx;
|
||||
margin-bottom: 15rpx;
|
||||
|
||||
.content-html {
|
||||
font-size: 26rpx;
|
||||
line-height: 1.5;
|
||||
color: #666;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.image-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 15rpx;
|
||||
gap: 10rpx;
|
||||
|
||||
.comment-image {
|
||||
width: 150rpx;
|
||||
height: 150rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sub-comment-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-left: 55rpx;
|
||||
|
||||
.time {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.action-btns {
|
||||
display: flex;
|
||||
gap: 15rpx;
|
||||
|
||||
.action-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6rpx;
|
||||
|
||||
.btn-text {
|
||||
font-size: 22rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.load-more-replies {
|
||||
text-align: center;
|
||||
padding: 15rpx 0;
|
||||
margin-top: 15rpx;
|
||||
|
||||
text {
|
||||
font-size: 24rpx;
|
||||
color: #2979ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.load-more-btn {
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.no-more {
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.no-comments {
|
||||
text-align: center;
|
||||
padding: 80rpx 0;
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user