|
@@ -1,125 +1,427 @@
|
|
|
<template>
|
|
<template>
|
|
|
<el-card class="comment-card shadow-box">
|
|
<el-card class="comment-card shadow-box">
|
|
|
- <div slot="header" class="comment-header">
|
|
|
|
|
- <span>全部评论 <small>{{ totalSize }}</small></span>
|
|
|
|
|
- </div>
|
|
|
|
|
<div class="comment-container">
|
|
<div class="comment-container">
|
|
|
- <comment
|
|
|
|
|
- v-model="dataList"
|
|
|
|
|
- :user="currentUser"
|
|
|
|
|
- :props="commentProps"
|
|
|
|
|
- :before-submit="submit"
|
|
|
|
|
- :before-like="like"
|
|
|
|
|
- :before-delete="deleteComment"
|
|
|
|
|
- :upload-img="uploadImg"
|
|
|
|
|
- />
|
|
|
|
|
- <div class="pagination-wrapper">
|
|
|
|
|
- <el-pagination
|
|
|
|
|
- :small="screenWidth <= 768"
|
|
|
|
|
- hide-on-single-page
|
|
|
|
|
- background
|
|
|
|
|
- layout="prev, pager, next"
|
|
|
|
|
- :page-size="pageSize"
|
|
|
|
|
- :current-page="currentPage"
|
|
|
|
|
- :total="totalSize"
|
|
|
|
|
- @current-change="handleCurrentChange"
|
|
|
|
|
|
|
+ <div class="comment-header">
|
|
|
|
|
+ <span class="total-count">{{ totalSize }} 评论</span>
|
|
|
|
|
+ <div class="sort-options">
|
|
|
|
|
+ <span :class="{ active: sortType === 'hot' }" @click="handleSort('hot')">最热</span>
|
|
|
|
|
+ <el-divider direction="vertical" />
|
|
|
|
|
+ <span :class="{ active: sortType === 'time' }" @click="handleSort('time')">最新</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="main-reply-box">
|
|
|
|
|
+ <el-avatar
|
|
|
|
|
+ :size="48"
|
|
|
|
|
+ :src="currentUser.avatar || defaultAvatar"
|
|
|
|
|
+ class="clickable-avatar"
|
|
|
|
|
+ @click.native="goToUserHome(currentUser.userId)"
|
|
|
/>
|
|
/>
|
|
|
|
|
+ <div class="reply-input-wrapper">
|
|
|
|
|
+ <el-input
|
|
|
|
|
+ v-model="newComment"
|
|
|
|
|
+ type="textarea"
|
|
|
|
|
+ :rows="3"
|
|
|
|
|
+ placeholder="发一条友善的评论吧"
|
|
|
|
|
+ resize="none"
|
|
|
|
|
+ />
|
|
|
|
|
+ <el-button type="primary" class="post-btn" @click="postMainComment">发表评论</el-button>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-infinite-scroll="loadMoreMainComments"
|
|
|
|
|
+ class="comment-list"
|
|
|
|
|
+ :infinite-scroll-disabled="mainScrollDisabled"
|
|
|
|
|
+ :infinite-scroll-distance="20"
|
|
|
|
|
+ >
|
|
|
|
|
+ <div v-for="item in dataList" :key="item.id" class="comment-item">
|
|
|
|
|
+ <div class="comment-root">
|
|
|
|
|
+ <el-avatar
|
|
|
|
|
+ :size="48"
|
|
|
|
|
+ :src="item.user.avatar || defaultAvatar"
|
|
|
|
|
+ class="clickable-avatar"
|
|
|
|
|
+ @click.native="goToUserHome(item.user.userId || item.user.id)"
|
|
|
|
|
+ />
|
|
|
|
|
+ <div class="comment-content">
|
|
|
|
|
+ <div class="user-info">
|
|
|
|
|
+ <span class="user-name clickable-link" @click="goToUserHome(item.user.userId || item.user.id)">
|
|
|
|
|
+ {{ item.user.name }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <p class="text">{{ item.content }}</p>
|
|
|
|
|
+ <div class="comment-footer">
|
|
|
|
|
+ <span class="time">{{ formatDate(item.createAt) }}</span>
|
|
|
|
|
+ <span class="action" @click="showReplyInput(item, item)">回复</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div v-if="item.total > 0" class="reply-list">
|
|
|
|
|
+ <div v-for="reply in item.children.slice(0, 3)" :key="reply.id" class="reply-item">
|
|
|
|
|
+ <el-avatar
|
|
|
|
|
+ :size="24"
|
|
|
|
|
+ :src="reply.user.avatar || defaultAvatar"
|
|
|
|
|
+ class="reply-avatar clickable-avatar"
|
|
|
|
|
+ @click.native="goToUserHome(reply.user.userId || reply.user.id)"
|
|
|
|
|
+ />
|
|
|
|
|
+ <div class="reply-right">
|
|
|
|
|
+ <span class="user-name clickable-link" @click="goToUserHome(reply.user.userId || reply.user.id)">
|
|
|
|
|
+ {{ reply.user.name }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <span v-if="reply.targetId && reply.targetId !== item.id">
|
|
|
|
|
+ 回复
|
|
|
|
|
+ <span class="target-name clickable-link" @click="goToUserHome(reply.targetUserId)">
|
|
|
|
|
+ @{{ reply.targetUsername }}
|
|
|
|
|
+ </span> :
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <span class="reply-content">{{ reply.content }}</span>
|
|
|
|
|
+ <span class="sub-action" @click="showReplyInput(item, reply)">回复</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div v-if="item.total > 3" class="view-more-bar">
|
|
|
|
|
+ 共 {{ item.total }} 条回复,
|
|
|
|
|
+ <span class="click-more" @click="openReplyDialog(item)">点击查看更多</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div v-if="activeRootId === item.id && !dialogVisible" class="inner-reply-box">
|
|
|
|
|
+ <el-input v-model="replyText" size="small" :placeholder="replyPlaceholder" />
|
|
|
|
|
+ <el-button type="primary" size="small" @click="postReply">发布</el-button>
|
|
|
|
|
+ <el-button type="text" size="small" @click="activeRootId = null">取消</el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <el-divider />
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <p v-if="loading" class="list-status">加载中...</p>
|
|
|
|
|
+ <p v-if="noMoreMain && dataList.length > 0" class="list-status">没有更多评论了</p>
|
|
|
|
|
+ <el-empty v-if="!loading && dataList.length === 0" description="暂无评论,快来抢沙发" />
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <el-dialog :visible.sync="dialogVisible" title="评论详情" width="600px" :append-to-body="true" custom-class="reply-dialog" @close="activeRootId = null">
|
|
|
|
|
+ <div v-if="currentParent" class="dialog-scroll-area">
|
|
|
|
|
+ <div class="parent-info">
|
|
|
|
|
+ <el-avatar
|
|
|
|
|
+ :size="40"
|
|
|
|
|
+ :src="currentParent.user.avatar || defaultAvatar"
|
|
|
|
|
+ class="clickable-avatar"
|
|
|
|
|
+ @click.native="goToUserHome(currentParent.user.userId || currentParent.user.id)"
|
|
|
|
|
+ />
|
|
|
|
|
+ <div class="parent-text">
|
|
|
|
|
+ <div class="user-name clickable-link" @click="goToUserHome(currentParent.user.userId || currentParent.user.id)">
|
|
|
|
|
+ {{ currentParent.user.name }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="content">{{ currentParent.content }}</div>
|
|
|
|
|
+ <div class="reply-footer">
|
|
|
|
|
+ <span class="time">{{ formatDate(currentParent.createAt) }}</span>
|
|
|
|
|
+ <span class="action" @click="showReplyInput(currentParent, currentParent)">回复</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <el-divider content-position="left">全部回复 ({{ currentParent.total }})</el-divider>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="dialog-reply-list">
|
|
|
|
|
+ <div v-for="sub in dialogReplies" :key="sub.id" class="dialog-reply-item">
|
|
|
|
|
+ <el-avatar
|
|
|
|
|
+ :size="32"
|
|
|
|
|
+ :src="sub.user.avatar || defaultAvatar"
|
|
|
|
|
+ class="clickable-avatar"
|
|
|
|
|
+ @click.native="goToUserHome(sub.user.userId || sub.user.id)"
|
|
|
|
|
+ />
|
|
|
|
|
+ <div class="reply-body">
|
|
|
|
|
+ <span class="user-name clickable-link" @click="goToUserHome(sub.user.userId || sub.user.id)">
|
|
|
|
|
+ {{ sub.user.name }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <span v-if="sub.targetId && sub.targetId !== currentParent.id">
|
|
|
|
|
+ 回复
|
|
|
|
|
+ <span class="target-name clickable-link" @click="goToUserHome(sub.targetUserId)">
|
|
|
|
|
+ @{{ sub.targetUsername }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </span>: {{ sub.content }}
|
|
|
|
|
+ <div class="reply-footer">
|
|
|
|
|
+ {{ formatDate(sub.createAt) }}
|
|
|
|
|
+ <span class="action" @click="showReplyInput(currentParent, sub)">回复</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="dialog-pagination">
|
|
|
|
|
+ <el-pagination
|
|
|
|
|
+ small
|
|
|
|
|
+ background
|
|
|
|
|
+ layout="prev, pager, next"
|
|
|
|
|
+ :total="currentParent.total"
|
|
|
|
|
+ :page-size="childPageSize"
|
|
|
|
|
+ :current-page.sync="childCurrentPage"
|
|
|
|
|
+ @current-change="handleChildPageChange"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div v-if="dialogVisible && activeRootId === currentParent.id" class="dialog-inner-reply">
|
|
|
|
|
+ <el-divider />
|
|
|
|
|
+ <div class="inner-reply-box">
|
|
|
|
|
+ <el-input v-model="replyText" size="small" :placeholder="replyPlaceholder" />
|
|
|
|
|
+ <el-button type="primary" size="small" @click="postReply">发布</el-button>
|
|
|
|
|
+ <el-button type="text" size="small" @click="activeRootId = null">取消</el-button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
</div>
|
|
|
</el-card>
|
|
</el-card>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
<script>
|
|
|
-import comment from '@/components/comment'
|
|
|
|
|
-import { publishComment, getComment } from '@/api/comment'
|
|
|
|
|
|
|
+import { getChildComment, getComment, publishComment } from '@/api/comment'
|
|
|
|
|
|
|
|
export default {
|
|
export default {
|
|
|
name: 'UserCommentCard',
|
|
name: 'UserCommentCard',
|
|
|
- components: { comment },
|
|
|
|
|
props: {
|
|
props: {
|
|
|
videoId: { type: String, required: true },
|
|
videoId: { type: String, required: true },
|
|
|
- currentUser: { type: Object, required: true },
|
|
|
|
|
- screenWidth: { type: Number, default: 1200 }
|
|
|
|
|
|
|
+ currentUser: { type: Object, default: () => ({ userId: -1, name: '游客', avatar: '' }) }
|
|
|
},
|
|
},
|
|
|
data() {
|
|
data() {
|
|
|
return {
|
|
return {
|
|
|
- currentPage: 1,
|
|
|
|
|
- pageSize: 20,
|
|
|
|
|
- totalSize: 0,
|
|
|
|
|
dataList: [],
|
|
dataList: [],
|
|
|
- commentProps: {
|
|
|
|
|
- id: 'commentId',
|
|
|
|
|
- content: 'content',
|
|
|
|
|
- imgSrc: 'imageUrl',
|
|
|
|
|
- children: 'children',
|
|
|
|
|
- likes: 'likes',
|
|
|
|
|
- liked: 'liked',
|
|
|
|
|
- reply: 'reply',
|
|
|
|
|
- createAt: 'createAt',
|
|
|
|
|
- total: 'total',
|
|
|
|
|
- user: 'user'
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ totalSize: 0,
|
|
|
|
|
+ currentPage: 0,
|
|
|
|
|
+ pageSize: 10,
|
|
|
|
|
+ loading: false,
|
|
|
|
|
+ noMoreMain: false,
|
|
|
|
|
+ sortType: 'hot',
|
|
|
|
|
+ dialogVisible: false,
|
|
|
|
|
+ currentParent: null,
|
|
|
|
|
+ dialogReplies: [],
|
|
|
|
|
+ childCurrentPage: 1,
|
|
|
|
|
+ childPageSize: 10,
|
|
|
|
|
+ newComment: '',
|
|
|
|
|
+ replyText: '',
|
|
|
|
|
+ activeRootId: null,
|
|
|
|
|
+ replyTarget: null,
|
|
|
|
|
+ replyPlaceholder: '',
|
|
|
|
|
+ defaultAvatar: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png'
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ computed: {
|
|
|
|
|
+ mainScrollDisabled() {
|
|
|
|
|
+ return this.loading || this.noMoreMain
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
watch: {
|
|
watch: {
|
|
|
videoId: {
|
|
videoId: {
|
|
|
immediate: true,
|
|
immediate: true,
|
|
|
- handler(newVal) {
|
|
|
|
|
- if (newVal) this.getCommentWrapper(1)
|
|
|
|
|
|
|
+ handler(val) {
|
|
|
|
|
+ if (val) this.initCommentList()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
methods: {
|
|
methods: {
|
|
|
- handleCurrentChange(page) {
|
|
|
|
|
- this.currentPage = page
|
|
|
|
|
- this.getCommentWrapper(page)
|
|
|
|
|
- window.scrollTo({ top: document.querySelector('.comment-card').offsetTop - 100, behavior: 'smooth' })
|
|
|
|
|
|
|
+ goToUserHome(userId) {
|
|
|
|
|
+ this.$message.info('goto userhome ' + userId)
|
|
|
},
|
|
},
|
|
|
- getCommentWrapper(pageNumber) {
|
|
|
|
|
- getComment(this.videoId, pageNumber).then(resp => {
|
|
|
|
|
|
|
+ initCommentList() {
|
|
|
|
|
+ this.dataList = []
|
|
|
|
|
+ this.currentPage = 0
|
|
|
|
|
+ this.noMoreMain = false
|
|
|
|
|
+ this.loadMoreMainComments()
|
|
|
|
|
+ },
|
|
|
|
|
+ async loadMoreMainComments() {
|
|
|
|
|
+ if (this.loading || this.noMoreMain) return
|
|
|
|
|
+ this.loading = true
|
|
|
|
|
+ this.currentPage++
|
|
|
|
|
+ try {
|
|
|
|
|
+ const resp = await getComment({
|
|
|
|
|
+ videoId: this.videoId,
|
|
|
|
|
+ pn: this.currentPage,
|
|
|
|
|
+ pageSize: this.pageSize,
|
|
|
|
|
+ sortBy: this.sortType
|
|
|
|
|
+ })
|
|
|
if (resp.code === 0) {
|
|
if (resp.code === 0) {
|
|
|
- this.dataList = resp.data.list
|
|
|
|
|
|
|
+ const newList = resp.data.list || []
|
|
|
|
|
+ this.dataList = [...this.dataList, ...newList]
|
|
|
this.totalSize = resp.data.totalSize
|
|
this.totalSize = resp.data.totalSize
|
|
|
- } else {
|
|
|
|
|
- this.$message.error(resp.msg)
|
|
|
|
|
|
|
+ if (newList.length < this.pageSize || this.dataList.length >= this.totalSize) {
|
|
|
|
|
+ this.noMoreMain = true
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- }).catch(err => this.$message.error(err.message))
|
|
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.error('加载失败', e)
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ this.loading = false
|
|
|
|
|
+ }
|
|
|
},
|
|
},
|
|
|
- async submit(newComment, parent, add) {
|
|
|
|
|
- // 模拟延迟
|
|
|
|
|
- await new Promise(resolve => setTimeout(resolve, 300))
|
|
|
|
|
-
|
|
|
|
|
- const payload = { newComment, parent, postId: this.videoId }
|
|
|
|
|
- publishComment(payload).then(resp => {
|
|
|
|
|
|
|
+ handleSort(type) {
|
|
|
|
|
+ this.sortType = type
|
|
|
|
|
+ this.initCommentList()
|
|
|
|
|
+ },
|
|
|
|
|
+ showReplyInput(root, target) {
|
|
|
|
|
+ this.activeRootId = root.id
|
|
|
|
|
+ this.replyTarget = target
|
|
|
|
|
+ this.replyPlaceholder = `回复 @${target.user.name} :`
|
|
|
|
|
+ this.replyText = ''
|
|
|
|
|
+ },
|
|
|
|
|
+ postMainComment() {
|
|
|
|
|
+ if (!this.newComment.trim()) return
|
|
|
|
|
+ publishComment({
|
|
|
|
|
+ videoId: this.videoId,
|
|
|
|
|
+ content: this.newComment,
|
|
|
|
|
+ parentId: 0,
|
|
|
|
|
+ targetId: 0
|
|
|
|
|
+ }).then(resp => {
|
|
|
if (resp.code === 0) {
|
|
if (resp.code === 0) {
|
|
|
- add(Object.assign(newComment, { postId: this.videoId }))
|
|
|
|
|
- if (parent === null) this.totalSize += 1
|
|
|
|
|
- this.$notify.success({ message: '评论已发布' })
|
|
|
|
|
- } else {
|
|
|
|
|
- this.$notify.warning({ message: '评论发布失败' })
|
|
|
|
|
|
|
+ this.$message.success('评论成功')
|
|
|
|
|
+ this.newComment = ''
|
|
|
|
|
+ this.initCommentList()
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
},
|
|
},
|
|
|
- async like(comment) {
|
|
|
|
|
- console.log('Like comment:', comment)
|
|
|
|
|
- // 这里可以调用点赞接口
|
|
|
|
|
|
|
+ postReply() {
|
|
|
|
|
+ if (!this.replyText.trim()) return
|
|
|
|
|
+ publishComment({
|
|
|
|
|
+ videoId: this.videoId,
|
|
|
|
|
+ content: this.replyText,
|
|
|
|
|
+ parentId: this.activeRootId,
|
|
|
|
|
+ targetId: this.replyTarget.id,
|
|
|
|
|
+ targetUsername: this.replyTarget.user.name
|
|
|
|
|
+ }).then(resp => {
|
|
|
|
|
+ if (resp.code === 0) {
|
|
|
|
|
+ this.$message.success('回复成功')
|
|
|
|
|
+ this.replyText = ''
|
|
|
|
|
+ // 不再直接置 null,如果想让用户连续回复可以保持,但通常交互是关闭
|
|
|
|
|
+ this.activeRootId = null
|
|
|
|
|
+ if (this.dialogVisible) {
|
|
|
|
|
+ this.fetchDialogReplies(this.currentParent.id, this.childCurrentPage)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 如果在主列表回复,可能需要刷新子列表或重新获取
|
|
|
|
|
+ this.initCommentList()
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
},
|
|
},
|
|
|
- async deleteComment(comment, parent) {
|
|
|
|
|
- console.log('Delete comment:', comment)
|
|
|
|
|
- // 这里可以调用删除接口
|
|
|
|
|
|
|
+ async openReplyDialog(parentItem) {
|
|
|
|
|
+ this.currentParent = parentItem
|
|
|
|
|
+ this.childCurrentPage = 1
|
|
|
|
|
+ this.dialogVisible = true
|
|
|
|
|
+ this.activeRootId = null // 重置输入框状态
|
|
|
|
|
+ this.fetchDialogReplies(parentItem.id, 1)
|
|
|
},
|
|
},
|
|
|
- async uploadImg({ file, callback }) {
|
|
|
|
|
- const reader = new FileReader()
|
|
|
|
|
- reader.readAsDataURL(file)
|
|
|
|
|
- reader.onload = () => callback(reader.result)
|
|
|
|
|
|
|
+ fetchDialogReplies(commentId, pageNumber) {
|
|
|
|
|
+ getChildComment({ commentId, pn: pageNumber }).then(resp => {
|
|
|
|
|
+ if (resp.code === 0) {
|
|
|
|
|
+ this.dialogReplies = resp.data.list
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ handleChildPageChange(page) {
|
|
|
|
|
+ this.fetchDialogReplies(this.currentParent.id, page)
|
|
|
|
|
+ },
|
|
|
|
|
+ formatDate(ts) {
|
|
|
|
|
+ if (!ts) return ''
|
|
|
|
|
+ const date = new Date(ts)
|
|
|
|
|
+ return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
-<style scoped>
|
|
|
|
|
-.comment-card { margin-bottom: 40px; }
|
|
|
|
|
-.comment-header { font-weight: 600; font-size: 18px; }
|
|
|
|
|
-.comment-header small { font-weight: normal; color: #909399; margin-left: 8px; }
|
|
|
|
|
-.pagination-wrapper { margin-top: 30px; display: flex; justify-content: center; }
|
|
|
|
|
|
|
+<style scoped lang="scss">
|
|
|
|
|
+.comment-card { margin-top: 20px; border: none; }
|
|
|
|
|
+.comment-container { color: #18191c; }
|
|
|
|
|
+
|
|
|
|
|
+.clickable-avatar {
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ transition: opacity 0.2s;
|
|
|
|
|
+ &:hover { opacity: 0.8; }
|
|
|
|
|
+}
|
|
|
|
|
+.clickable-link {
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+ &:hover { color: #00aeec !important; }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.comment-header {
|
|
|
|
|
+ margin-bottom: 24px; display: flex; align-items: center;
|
|
|
|
|
+ .total-count { font-size: 18px; font-weight: 500; margin-right: 20px; }
|
|
|
|
|
+ .sort-options span { font-size: 14px; color: #9499a0; cursor: pointer; &.active { color: #18191c; font-weight: bold; } }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.main-reply-box {
|
|
|
|
|
+ display: flex; gap: 15px; margin-bottom: 30px;
|
|
|
|
|
+ .reply-input-wrapper { flex: 1; .post-btn { margin-top: 10px; float: right; } }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.comment-list { min-height: 200px; }
|
|
|
|
|
+.list-status { text-align: center; color: #9499a0; font-size: 13px; padding: 20px 0; }
|
|
|
|
|
+.comment-root {
|
|
|
|
|
+ display: flex; gap: 15px;
|
|
|
|
|
+ .comment-content {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ .user-name { font-size: 13px; font-weight: bold; color: #61666d; }
|
|
|
|
|
+ .text { font-size: 15px; line-height: 1.6; margin: 8px 0; }
|
|
|
|
|
+ .comment-footer {
|
|
|
|
|
+ font-size: 13px; color: #9499a0; display: flex; gap: 20px; margin-bottom: 8px;
|
|
|
|
|
+ .action { cursor: pointer; &:hover { color: #00aeec; } }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.reply-list {
|
|
|
|
|
+ background: #f6f7f8; border-radius: 6px; padding: 12px;
|
|
|
|
|
+ .reply-item {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+ font-size: 14px; line-height: 22px; margin-bottom: 8px;
|
|
|
|
|
+ .reply-avatar { flex-shrink: 0; margin-top: 2px; }
|
|
|
|
|
+ .reply-right { flex: 1; }
|
|
|
|
|
+ .user-name { color: #61666d; font-weight: bold; margin-right: 5px; }
|
|
|
|
|
+ .target-name { color: #00aeec; font-weight: 500; margin: 0 4px; }
|
|
|
|
|
+ .sub-action {
|
|
|
|
|
+ margin-left: 10px; font-size: 12px; color: #9499a0; cursor: pointer;
|
|
|
|
|
+ display: none;
|
|
|
|
|
+ }
|
|
|
|
|
+ &:hover .sub-action { display: inline-block; }
|
|
|
|
|
+ }
|
|
|
|
|
+ .view-more-bar {
|
|
|
|
|
+ font-size: 13px; color: #9499a0; margin-top: 8px; padding-left: 32px;
|
|
|
|
|
+ .click-more { color: #00aeec; cursor: pointer; font-weight: 500; }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.inner-reply-box {
|
|
|
|
|
+ margin-top: 10px; display: flex; gap: 8px;
|
|
|
|
|
+ background: #fff; padding: 10px; border: 1px solid #e3e5e7; border-radius: 6px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.dialog-scroll-area {
|
|
|
|
|
+ max-height: 50vh; overflow-y: auto; padding-right: 8px;
|
|
|
|
|
+ .parent-info {
|
|
|
|
|
+ display: flex; gap: 12px;
|
|
|
|
|
+ .parent-text {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ .user-name { font-weight: bold; color: #61666d; margin-bottom: 4px; }
|
|
|
|
|
+ .content { font-size: 15px; line-height: 1.6; margin-bottom: 8px; }
|
|
|
|
|
+ .reply-footer { font-size: 12px; color: #9499a0; .action { margin-left: 15px; cursor: pointer; &:hover { color: #00aeec; } } }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .dialog-reply-item {
|
|
|
|
|
+ display: flex; gap: 10px; margin-bottom: 15px;
|
|
|
|
|
+ .reply-body {
|
|
|
|
|
+ flex: 1; font-size: 14px;
|
|
|
|
|
+ .user-name { font-weight: bold; color: #61666d; }
|
|
|
|
|
+ .target-name { color: #00aeec; margin: 0 4px; }
|
|
|
|
|
+ .reply-footer { font-size: 12px; color: #9499a0; margin-top: 5px;
|
|
|
|
|
+ .action { margin-left: 10px; cursor: pointer; &:hover { color: #00aeec; } }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ .dialog-pagination { display: flex; justify-content: center; margin-top: 20px; }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* 弹窗专用回复框样式 */
|
|
|
|
|
+.dialog-inner-reply {
|
|
|
|
|
+ padding-top: 0;
|
|
|
|
|
+ .el-divider--horizontal { margin: 12px 0; }
|
|
|
|
|
+}
|
|
|
</style>
|
|
</style>
|