feat: menu

This commit is contained in:
tim
2025-07-11 15:25:02 +08:00
parent 15749ae5e2
commit cb484fa53a
3 changed files with 46 additions and 35 deletions

View File

@@ -1,11 +1,7 @@
<template> <template>
<div <div class="info-content-container" :id="'comment-' + comment.id" :style="{
class="info-content-container"
:id="'comment-' + comment.id"
:style="{
...(level > 0 ? { /*borderLeft: '1px solid #e0e0e0', */borderBottom: 'none' } : {}) ...(level > 0 ? { /*borderLeft: '1px solid #e0e0e0', */borderBottom: 'none' } : {})
}" }">
>
<!-- <div class="user-avatar-container"> <!-- <div class="user-avatar-container">
<div class="user-avatar-item"> <div class="user-avatar-item">
<img class="user-avatar-item-img" :src="comment.avatar" alt="avatar" /> <img class="user-avatar-item-img" :src="comment.avatar" alt="avatar" />
@@ -13,9 +9,18 @@
</div> --> </div> -->
<div class="info-content"> <div class="info-content">
<div class="info-content-header"> <div class="info-content-header">
<div class="info-content-header-left">
<div class="user-name">{{ comment.userName }}</div> <div class="user-name">{{ comment.userName }}</div>
<div class="post-time">{{ comment.time }}</div> <div class="post-time">{{ comment.time }}</div>
</div> </div>
<div class="info-content-header-right">
<DropdownMenu :items="commentMenuItems">
<template #trigger>
<i class="fas fa-ellipsis-vertical action-menu-icon"></i>
</template>
</DropdownMenu>
</div>
</div>
<div class="info-content-text" v-html="renderMarkdown(comment.text)"></div> <div class="info-content-text" v-html="renderMarkdown(comment.text)"></div>
<div class="article-footer-container"> <div class="article-footer-container">
<ReactionsGroup v-model="comment.reactions" content-type="comment" :content-id="comment.id"> <ReactionsGroup v-model="comment.reactions" content-type="comment" :content-id="comment.id">
@@ -28,25 +33,16 @@
</ReactionsGroup> </ReactionsGroup>
</div> </div>
<CommentEditor v-if="showEditor" @submit="submitReply" :loading="isWaitingForReply" /> <CommentEditor v-if="showEditor" @submit="submitReply" :loading="isWaitingForReply" />
<div <div v-if="comment.reply && comment.reply.length" class="reply-toggle" @click="toggleReplies">
v-if="comment.reply && comment.reply.length"
class="reply-toggle"
@click="toggleReplies"
>
<i v-if="showReplies" class="fas fa-chevron-up reply-toggle-icon"></i> <i v-if="showReplies" class="fas fa-chevron-up reply-toggle-icon"></i>
<i v-else class="fas fa-chevron-down reply-toggle-icon"></i> <i v-else class="fas fa-chevron-down reply-toggle-icon"></i>
{{ comment.reply.length }}条回复 {{ comment.reply.length }}条回复
</div> </div>
<div v-if="showReplies" class="reply-list"> <div v-if="showReplies" class="reply-list">
<BaseTimeline :items="comment.reply" > <BaseTimeline :items="comment.reply">
<template #item="{ item }"> <template #item="{ item }">
<CommentItem <CommentItem :key="item.id" :comment="item" :level="level + 1" :default-show-replies="item.openReplies" />
:key="item.id"
:comment="item"
:level="level + 1"
:default-show-replies="item.openReplies"
/>
</template> </template>
</BaseTimeline> </BaseTimeline>
<!-- <CommentItem <!-- <CommentItem
@@ -71,6 +67,7 @@ import BaseTimeline from './BaseTimeline.vue'
import { API_BASE_URL, toast } from '../main' import { API_BASE_URL, toast } from '../main'
import { getToken } from '../utils/auth' import { getToken } from '../utils/auth'
import ReactionsGroup from './ReactionsGroup.vue' import ReactionsGroup from './ReactionsGroup.vue'
import DropdownMenu from './DropdownMenu.vue'
const CommentItem = { const CommentItem = {
name: 'CommentItem', name: 'CommentItem',
props: { props: {
@@ -104,6 +101,11 @@ const CommentItem = {
const toggleEditor = () => { const toggleEditor = () => {
showEditor.value = !showEditor.value showEditor.value = !showEditor.value
} }
const commentMenuItems = ref([
{ text: '删除评论', color: 'red', onClick: () => deleteComment() }
])
const deleteComment = () => {
}
const submitReply = async (text) => { const submitReply = async (text) => {
if (!text.trim()) return if (!text.trim()) return
isWaitingForReply.value = true isWaitingForReply.value = true
@@ -162,10 +164,12 @@ const CommentItem = {
toast.success('已复制') toast.success('已复制')
}) })
} }
return { showReplies, toggleReplies, showEditor, toggleEditor, submitReply, copyCommentLink, renderMarkdown, isWaitingForReply } return { showReplies, toggleReplies, showEditor, toggleEditor, submitReply, copyCommentLink, renderMarkdown, isWaitingForReply, commentMenuItems, deleteComment }
} }
} }
CommentItem.components = { CommentItem, CommentEditor, BaseTimeline, ReactionsGroup }
CommentItem.components = { CommentItem, CommentEditor, BaseTimeline, ReactionsGroup, DropdownMenu }
export default CommentItem export default CommentItem
</script> </script>
@@ -176,8 +180,7 @@ export default CommentItem
user-select: none; user-select: none;
} }
.reply-list { .reply-list {}
}
.comment-reaction { .comment-reaction {
color: var(--primary-color); color: var(--primary-color);
@@ -196,8 +199,12 @@ export default CommentItem
} }
@keyframes highlight { @keyframes highlight {
from { background-color: yellow; } from {
to { background-color: transparent; } background-color: yellow;
} }
to {
background-color: transparent;
}
}
</style> </style>

View File

@@ -225,7 +225,7 @@ export default {
const iconMap = { const iconMap = {
POST_VIEWED: 'fas fa-eye', POST_VIEWED: 'fas fa-eye',
COMMENT_REPLY: 'fas fa-reply', COMMENT_REPLY: 'fas fa-reply',
POST_REVIEWED: 'fas fa-check', POST_REVIEWED: 'fas fa-shield-alt',
POST_REVIEW_REQUEST: 'fas fa-gavel', POST_REVIEW_REQUEST: 'fas fa-gavel',
POST_UPDATED: 'fas fa-comment-dots', POST_UPDATED: 'fas fa-comment-dots',
USER_ACTIVITY: 'fas fa-user', USER_ACTIVITY: 'fas fa-user',

View File

@@ -27,7 +27,7 @@
<i class="fas fa-user-minus"></i> <i class="fas fa-user-minus"></i>
取消订阅 取消订阅
</div> </div>
<DropdownMenu v-if="isAdmin && status === 'PENDING'" :items="reviewMenuItems"> <DropdownMenu :items="articleMenuItems">
<template #trigger> <template #trigger>
<i class="fas fa-ellipsis-vertical action-menu-icon"></i> <i class="fas fa-ellipsis-vertical action-menu-icon"></i>
</template> </template>
@@ -138,7 +138,8 @@ export default {
const loggedIn = computed(() => authState.loggedIn) const loggedIn = computed(() => authState.loggedIn)
const isAdmin = computed(() => authState.role === 'ADMIN') const isAdmin = computed(() => authState.role === 'ADMIN')
const isAuthor = computed(() => authState.username === author.value.username) const isAuthor = computed(() => authState.username === author.value.username)
const reviewMenuItems = [ const articleMenuItems = [
{ text: '删除文章', color: 'red', onClick: () => deletePost() },
{ text: '通过审核', onClick: () => approvePost() }, { text: '通过审核', onClick: () => approvePost() },
{ text: '驳回', color: 'red', onClick: () => rejectPost() } { text: '驳回', color: 'red', onClick: () => rejectPost() }
] ]
@@ -339,6 +340,9 @@ export default {
} }
} }
const deletePost = async () => {
}
const rejectPost = async () => { const rejectPost = async () => {
const token = getToken() const token = getToken()
if (!token) return if (!token) return
@@ -415,7 +419,7 @@ export default {
currentIndex, currentIndex,
totalPosts, totalPosts,
postReactions, postReactions,
reviewMenuItems, articleMenuItems,
postId, postId,
postComment, postComment,
onSliderInput, onSliderInput,