Commit 3a7882f6 by lijiabin

【需求 21402】 feat: 文章评论区加入发布者本人删除评论功能

parent 7e251560
...@@ -135,6 +135,7 @@ ...@@ -135,6 +135,7 @@
<span class="font-semibold text-gray-800">{{ <span class="font-semibold text-gray-800">{{
isReal ? item.replyUser : item.hiddenName isReal ? item.replyUser : item.hiddenName
}}</span> }}</span>
<span <span
v-if="item.isTop === BooleanFlag.YES" v-if="item.isTop === BooleanFlag.YES"
class="inline-flex items-center gap-1 px-2 py-0.5 text-13px leading-4 font-medium text-amber-700 bg-amber-50/80 border border-amber-200/70 rounded-full" class="inline-flex items-center gap-1 px-2 py-0.5 text-13px leading-4 font-medium text-amber-700 bg-amber-50/80 border border-amber-200/70 rounded-full"
...@@ -150,6 +151,13 @@ ...@@ -150,6 +151,13 @@
> >
{{ item.floorNumber || '顶' }}楼 {{ item.floorNumber || '顶' }}楼
</span> </span>
<button
v-if="isSelfComment(item)"
class="cursor-pointer text-red-500 text-xs leading-none"
@click="handleDeleteComment(item)"
>
删除
</button>
</div> </div>
<!-- 作者有权利置顶 并且不是问吧(问吧是获取的二级评论列表) --> <!-- 作者有权利置顶 并且不是问吧(问吧是获取的二级评论列表) -->
<button <button
...@@ -249,10 +257,17 @@ ...@@ -249,10 +257,17 @@
child.replyUser child.replyUser
}}</span> }}</span>
<!-- v-if="item.replyName && item.replyName !== parentComment?.replyUser" --> <!-- v-if="item.replyName && item.replyName !== parentComment?.replyUser" -->
<span class="text-gray-500 text-sm flex items-center gap-1"> <span class="text-gray-500 text-sm flex items-center gap-1 px-1">
<el-icon class="mx-1"><IEpCaretRight /></el-icon> <el-icon class="mx-1"><IEpCaretRight /></el-icon>
{{ child.replyName }} {{ child.replyName }}
</span> </span>
<button
v-if="isSelfComment(child)"
class="cursor-pointer text-red-500 text-xs leading-none"
@click="handleDeleteComment(child)"
>
删除
</button>
</div> </div>
<p <p
class="text-gray-800 my-2 break-all whitespace-pre-wrap text-[16px]" class="text-gray-800 my-2 break-all whitespace-pre-wrap text-[16px]"
...@@ -430,8 +445,9 @@ import { ...@@ -430,8 +445,9 @@ import {
getCommentChildren, getCommentChildren,
getSecondCommentList, getSecondCommentList,
topOrCancelTopComment, topOrCancelTopComment,
deleteComment,
} from '@/api' } from '@/api'
import { usePageSearch, useScrollTop } from '@/hooks' import { useMessageBox, usePageSearch, useScrollTop } from '@/hooks'
import { ArticleTypeEnum, BooleanFlag } from '@/constants' import { ArticleTypeEnum, BooleanFlag } from '@/constants'
import type { CommentItemDto } from '@/api' import type { CommentItemDto } from '@/api'
import { useUserStore } from '@/stores' import { useUserStore } from '@/stores'
...@@ -445,6 +461,7 @@ import { push } from 'notivue' ...@@ -445,6 +461,7 @@ import { push } from 'notivue'
import { IS_REAL_KEY_COMMENT, CommentSortTypeEnum } from '@/constants' import { IS_REAL_KEY_COMMENT, CommentSortTypeEnum } from '@/constants'
const { jumpToUserHomePage } = useNavigation() const { jumpToUserHomePage } = useNavigation()
const { confirm } = useMessageBox()
const { const {
authorId = '', authorId = '',
id, id,
...@@ -556,6 +573,8 @@ const myCommentImgStr = ref('') ...@@ -556,6 +573,8 @@ const myCommentImgStr = ref('')
const commentToOtherImgStr = ref('') const commentToOtherImgStr = ref('')
const currentCommentId = ref(-1) const currentCommentId = ref(-1)
const myCommentBoxRef = useTemplateRef<InstanceType<typeof CommentBox>>('myCommentBoxRef') const myCommentBoxRef = useTemplateRef<InstanceType<typeof CommentBox>>('myCommentBoxRef')
const isSelfComment = (item: CommentItemDto) =>
String(item.userId || '') === String(userInfo.value.userId || '')
const handleLickComment = async (item: CommentItemDto) => { const handleLickComment = async (item: CommentItemDto) => {
await addOrCancelCommentLike(item.id) await addOrCancelCommentLike(item.id)
...@@ -570,6 +589,18 @@ const handleLickComment = async (item: CommentItemDto) => { ...@@ -570,6 +589,18 @@ const handleLickComment = async (item: CommentItemDto) => {
} }
} }
const handleDeleteComment = async (item: CommentItemDto) => {
await confirm({
title: '提示',
message: '确定删除该评论吗?',
type: 'danger',
})
await deleteComment(item.id)
push.success('删除成功')
await search()
emit('commentSuccess')
}
const highlightCommentId = ref<number | null>(null) const highlightCommentId = ref<number | null>(null)
const topCommentPendingId = ref<number | null>(null) const topCommentPendingId = ref<number | null>(null)
const handleTopComment = async (item: CommentItemDto) => { const handleTopComment = async (item: CommentItemDto) => {
......
...@@ -36,7 +36,17 @@ ...@@ -36,7 +36,17 @@
/> />
<div class="flex-1"> <div class="flex-1">
<div class="flex items-center justify-between mb-2"> <div class="flex items-center justify-between mb-2">
<div class="flex items-center gap-1.5">
<span class="font-bold text-gray-900 text-base">{{ parentComment.replyUser }}</span> <span class="font-bold text-gray-900 text-base">{{ parentComment.replyUser }}</span>
<button
v-if="isSelfComment(parentComment)"
class="cursor-pointer text-red-500 text-13px leading-none"
@click="handleDeleteComment(parentComment, true)"
>
删除
</button>
</div>
<div class="flex items-center gap-3">
<!-- 点赞按钮 --> <!-- 点赞按钮 -->
<div <div
class="flex items-center gap-1.5 cursor-pointer text-gray-500 hover:text-blue-500 transition-colors px-3 py-1.5 rounded-full hover:bg-blue-50" class="flex items-center gap-1.5 cursor-pointer text-gray-500 hover:text-blue-500 transition-colors px-3 py-1.5 rounded-full hover:bg-blue-50"
...@@ -48,6 +58,7 @@ ...@@ -48,6 +58,7 @@
<span class="text-sm font-medium">{{ parentComment.postPriseCount || 0 }}</span> <span class="text-sm font-medium">{{ parentComment.postPriseCount || 0 }}</span>
</div> </div>
</div> </div>
</div>
<div <div
class="text-gray-800 text-base leading-relaxed mb-2" class="text-gray-800 text-base leading-relaxed mb-2"
...@@ -101,6 +112,13 @@ ...@@ -101,6 +112,13 @@
<el-icon class="mx-1"><IEpCaretRight /></el-icon> <el-icon class="mx-1"><IEpCaretRight /></el-icon>
{{ item.replyName }} {{ item.replyName }}
</span> </span>
<button
v-if="isSelfComment(item)"
class="cursor-pointer text-red-500 text-13px leading-none"
@click="handleDeleteComment(item)"
>
删除
</button>
</div> </div>
<!-- 列表项点赞 --> <!-- 列表项点赞 -->
...@@ -234,6 +252,7 @@ import { ...@@ -234,6 +252,7 @@ import {
addComment, addComment,
addOrCancelCommentLike, addOrCancelCommentLike,
getCommentDetail, getCommentDetail,
deleteComment,
} from '@/api' } from '@/api'
import type { CommentItemDto } from '@/api' import type { CommentItemDto } from '@/api'
import { BooleanFlag } from '@/constants' import { BooleanFlag } from '@/constants'
...@@ -243,6 +262,7 @@ import CommentBox from '../CommentBox/index.vue' ...@@ -243,6 +262,7 @@ import CommentBox from '../CommentBox/index.vue'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { push } from 'notivue' import { push } from 'notivue'
import { IS_REAL_KEY_COMMENT } from '@/constants/symbolKey' import { IS_REAL_KEY_COMMENT } from '@/constants/symbolKey'
import { useMessageBox } from '@/hooks'
const { articleId, pid } = defineProps<{ const { articleId, pid } = defineProps<{
articleId: number articleId: number
...@@ -259,6 +279,7 @@ provide(IS_REAL_KEY_COMMENT, BooleanFlag.YES) ...@@ -259,6 +279,7 @@ provide(IS_REAL_KEY_COMMENT, BooleanFlag.YES)
const userStore = useUserStore() const userStore = useUserStore()
const { userInfo } = storeToRefs(userStore) const { userInfo } = storeToRefs(userStore)
const currentUserAvatar = computed(() => userInfo.value.hiddenAvatar) const currentUserAvatar = computed(() => userInfo.value.hiddenAvatar)
const { confirm } = useMessageBox()
// State // State
const visible = ref(false) const visible = ref(false)
...@@ -278,6 +299,8 @@ const commentStr = ref('') ...@@ -278,6 +299,8 @@ const commentStr = ref('')
const imgUrl = ref('') const imgUrl = ref('')
const loadingBtn = ref(false) const loadingBtn = ref(false)
const isDisabled = computed(() => !commentStr.value.trim() || loadingBtn.value) const isDisabled = computed(() => !commentStr.value.trim() || loadingBtn.value)
const isSelfComment = (item: CommentItemDto) =>
String(item.userId || '') === String(userInfo.value.userId || '')
// --- Actions --- // --- Actions ---
const { list, total, search, searchParams, goToPage, changePageSize, refresh, loading } = const { list, total, search, searchParams, goToPage, changePageSize, refresh, loading } =
...@@ -408,6 +431,23 @@ const handleLike = async (item: CommentItemDto) => { ...@@ -408,6 +431,23 @@ const handleLike = async (item: CommentItemDto) => {
} }
} }
const handleDeleteComment = async (item: CommentItemDto, isParent = false) => {
await confirm({
title: '提示',
message: '确定删除该评论吗?',
type: 'danger',
})
await deleteComment(item.id)
push.success('删除成功')
if (isParent) {
visible.value = false
emit('refresh')
return
}
await refresh()
emit('refresh')
}
const closeDialog = () => { const closeDialog = () => {
visible.value = false visible.value = false
} }
......
...@@ -300,10 +300,17 @@ ...@@ -300,10 +300,17 @@
置顶回答 置顶回答
</span> </span>
<span <span
class="inline-flex items-center rounded-full border border-gray-200 bg-gray-50 px-1.5 py-0.5 text-11px leading-none text-gray-500" class="inline-flex items-center rounded-full border border-gray-200 bg-gray-50 px-1.5 py-0.5 text-xs leading-none text-gray-500"
> >
{{ answer.floorNumber || '顶' }}楼 {{ answer.floorNumber || '顶' }}楼
</span> </span>
<button
v-if="isSelfAnswer(answer)"
class="cursor-pointer text-red-500 text-xs leading-none"
@click="handleDeleteAnswer(answer)"
>
删除
</button>
</div> </div>
</div> </div>
</div> </div>
...@@ -437,6 +444,7 @@ import { ...@@ -437,6 +444,7 @@ import {
addOrCanceArticlelCollect, addOrCanceArticlelCollect,
addOrCancelCommentLike, addOrCancelCommentLike,
topOrCancelTopComment, topOrCancelTopComment,
deleteComment,
} from '@/api' } from '@/api'
import type { ArticleItemDto, CommentItemDto } from '@/api' import type { ArticleItemDto, CommentItemDto } from '@/api'
import { usePageSearch } from '@/hooks' import { usePageSearch } from '@/hooks'
...@@ -448,6 +456,7 @@ import dayjs from 'dayjs' ...@@ -448,6 +456,7 @@ import dayjs from 'dayjs'
import { useUserStore } from '@/stores/user' import { useUserStore } from '@/stores/user'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { useNavigation, useScrollTop } from '@/hooks' import { useNavigation, useScrollTop } from '@/hooks'
import { useMessageBox } from '@/hooks'
import { parseEmoji } from '@/utils/emoji' import { parseEmoji } from '@/utils/emoji'
import { ArticleTypeEnum, BooleanFlag } from '@/constants' import { ArticleTypeEnum, BooleanFlag } from '@/constants'
import { push } from 'notivue' import { push } from 'notivue'
...@@ -456,6 +465,7 @@ import { CommentSortTypeEnum } from '@/constants' ...@@ -456,6 +465,7 @@ import { CommentSortTypeEnum } from '@/constants'
const userStore = useUserStore() const userStore = useUserStore()
const { userInfo } = storeToRefs(userStore) const { userInfo } = storeToRefs(userStore)
const { jumpToUserHomePage } = useNavigation() const { jumpToUserHomePage } = useNavigation()
const { confirm } = useMessageBox()
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
...@@ -471,6 +481,8 @@ const sendMessageDialogRef = useTemplateRef<InstanceType<typeof SendMessageDialo ...@@ -471,6 +481,8 @@ const sendMessageDialogRef = useTemplateRef<InstanceType<typeof SendMessageDialo
// 回滚到子评论框 // 回滚到子评论框
const { handleBackTop: handleBackTopChildren } = useScrollTop(answerRefList) const { handleBackTop: handleBackTopChildren } = useScrollTop(answerRefList)
const loading = computed(() => !questionDetail.value.title) const loading = computed(() => !questionDetail.value.title)
const isSelfAnswer = (answer: CommentItemDto) =>
String(answer.userId || '') === String(userInfo.value.userId || '')
const isAuthor = computed(() => { const isAuthor = computed(() => {
return questionDetail.value.createUserId === userInfo.value.userId return questionDetail.value.createUserId === userInfo.value.userId
...@@ -543,6 +555,17 @@ const handleLikeAnswer = async (answer: CommentItemDto) => { ...@@ -543,6 +555,17 @@ const handleLikeAnswer = async (answer: CommentItemDto) => {
push.success(`${answer.hasPraise ? '点赞该回答' : '取消点赞该回答'}`) push.success(`${answer.hasPraise ? '点赞该回答' : '取消点赞该回答'}`)
} }
const handleDeleteAnswer = async (answer: CommentItemDto) => {
await confirm({
title: '提示',
message: '确定删除该评论吗?',
type: 'danger',
})
await deleteComment(answer.id)
push.success('删除成功')
await refresh()
}
const topCommentPendingId = ref<number | null>(null) const topCommentPendingId = ref<number | null>(null)
const highlightCommentId = ref<number | null>(null) const highlightCommentId = ref<number | null>(null)
const handleTopAnswer = async (answer: CommentItemDto) => { const handleTopAnswer = async (answer: CommentItemDto) => {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment