Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
corporate-culture-qd
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
王立鹏
corporate-culture-qd
Commits
3a7882f6
Commit
3a7882f6
authored
Apr 28, 2026
by
lijiabin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
【需求 21402】 feat: 文章评论区加入发布者本人删除评论功能
parent
7e251560
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
107 additions
and
13 deletions
+107
-13
index.vue
src/components/common/Comment/index.vue
+33
-2
index.vue
src/components/common/CommentListDialog/index.vue
+50
-10
index.vue
src/views/questionDetail/index.vue
+24
-1
No files found.
src/components/common/Comment/index.vue
View file @
3a7882f6
...
...
@@ -135,6 +135,7 @@
<span
class=
"font-semibold text-gray-800"
>
{{
isReal ? item.replyUser : item.hiddenName
}}
</span>
<span
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"
...
...
@@ -150,6 +151,13 @@
>
{{ item.floorNumber || '顶' }}楼
</span>
<button
v-if=
"isSelfComment(item)"
class=
"cursor-pointer text-red-500 text-xs leading-none"
@
click=
"handleDeleteComment(item)"
>
删除
</button>
</div>
<!-- 作者有权利置顶 并且不是问吧(问吧是获取的二级评论列表) -->
<button
...
...
@@ -249,10 +257,17 @@
child
.
replyUser
}}
</span>
<!-- 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>
{{
child
.
replyName
}}
</span>
<button
v-if=
"isSelfComment(child)"
class=
"cursor-pointer text-red-500 text-xs leading-none"
@
click=
"handleDeleteComment(child)"
>
删除
</button>
</div>
<p
class=
"text-gray-800 my-2 break-all whitespace-pre-wrap text-[16px]"
...
...
@@ -430,8 +445,9 @@ import {
getCommentChildren
,
getSecondCommentList
,
topOrCancelTopComment
,
deleteComment
,
}
from
'@/api'
import
{
usePageSearch
,
useScrollTop
}
from
'@/hooks'
import
{
use
MessageBox
,
use
PageSearch
,
useScrollTop
}
from
'@/hooks'
import
{
ArticleTypeEnum
,
BooleanFlag
}
from
'@/constants'
import
type
{
CommentItemDto
}
from
'@/api'
import
{
useUserStore
}
from
'@/stores'
...
...
@@ -445,6 +461,7 @@ import { push } from 'notivue'
import
{
IS_REAL_KEY_COMMENT
,
CommentSortTypeEnum
}
from
'@/constants'
const
{
jumpToUserHomePage
}
=
useNavigation
()
const
{
confirm
}
=
useMessageBox
()
const
{
authorId
=
''
,
id
,
...
...
@@ -556,6 +573,8 @@ const myCommentImgStr = ref('')
const
commentToOtherImgStr
=
ref
(
''
)
const
currentCommentId
=
ref
(
-
1
)
const
myCommentBoxRef
=
useTemplateRef
<
InstanceType
<
typeof
CommentBox
>>
(
'myCommentBoxRef'
)
const
isSelfComment
=
(
item
:
CommentItemDto
)
=>
String
(
item
.
userId
||
''
)
===
String
(
userInfo
.
value
.
userId
||
''
)
const
handleLickComment
=
async
(
item
:
CommentItemDto
)
=>
{
await
addOrCancelCommentLike
(
item
.
id
)
...
...
@@ -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
topCommentPendingId
=
ref
<
number
|
null
>
(
null
)
const
handleTopComment
=
async
(
item
:
CommentItemDto
)
=>
{
...
...
src/components/common/CommentListDialog/index.vue
View file @
3a7882f6
...
...
@@ -36,16 +36,27 @@
/>
<div
class=
"flex-1"
>
<div
class=
"flex items-center justify-between mb-2"
>
<span
class=
"font-bold text-gray-900 text-base"
>
{{ parentComment.replyUser }}
</span>
<!-- 点赞按钮 -->
<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"
@
click=
"handleLike(parentComment)"
>
<el-icon
:size=
"18"
>
<svg-icon
:name=
"parentComment.hasPraise ? 'praise_fill' : 'praise'"
></svg-icon>
</el-icon>
<span
class=
"text-sm font-medium"
>
{{ parentComment.postPriseCount || 0 }}
</span>
<div
class=
"flex items-center gap-1.5"
>
<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
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"
@
click=
"handleLike(parentComment)"
>
<el-icon
:size=
"18"
>
<svg-icon
:name=
"parentComment.hasPraise ? 'praise_fill' : 'praise'"
></svg-icon>
</el-icon>
<span
class=
"text-sm font-medium"
>
{{ parentComment.postPriseCount || 0 }}
</span>
</div>
</div>
</div>
...
...
@@ -101,6 +112,13 @@
<el-icon
class=
"mx-1"
><IEpCaretRight
/></el-icon>
{{ item.replyName }}
</span>
<button
v-if=
"isSelfComment(item)"
class=
"cursor-pointer text-red-500 text-13px leading-none"
@
click=
"handleDeleteComment(item)"
>
删除
</button>
</div>
<!-- 列表项点赞 -->
...
...
@@ -234,6 +252,7 @@ import {
addComment
,
addOrCancelCommentLike
,
getCommentDetail
,
deleteComment
,
}
from
'@/api'
import
type
{
CommentItemDto
}
from
'@/api'
import
{
BooleanFlag
}
from
'@/constants'
...
...
@@ -243,6 +262,7 @@ import CommentBox from '../CommentBox/index.vue'
import
dayjs
from
'dayjs'
import
{
push
}
from
'notivue'
import
{
IS_REAL_KEY_COMMENT
}
from
'@/constants/symbolKey'
import
{
useMessageBox
}
from
'@/hooks'
const
{
articleId
,
pid
}
=
defineProps
<
{
articleId
:
number
...
...
@@ -259,6 +279,7 @@ provide(IS_REAL_KEY_COMMENT, BooleanFlag.YES)
const
userStore
=
useUserStore
()
const
{
userInfo
}
=
storeToRefs
(
userStore
)
const
currentUserAvatar
=
computed
(()
=>
userInfo
.
value
.
hiddenAvatar
)
const
{
confirm
}
=
useMessageBox
()
// State
const
visible
=
ref
(
false
)
...
...
@@ -278,6 +299,8 @@ const commentStr = ref('')
const
imgUrl
=
ref
(
''
)
const
loadingBtn
=
ref
(
false
)
const
isDisabled
=
computed
(()
=>
!
commentStr
.
value
.
trim
()
||
loadingBtn
.
value
)
const
isSelfComment
=
(
item
:
CommentItemDto
)
=>
String
(
item
.
userId
||
''
)
===
String
(
userInfo
.
value
.
userId
||
''
)
// --- Actions ---
const
{
list
,
total
,
search
,
searchParams
,
goToPage
,
changePageSize
,
refresh
,
loading
}
=
...
...
@@ -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
=
()
=>
{
visible
.
value
=
false
}
...
...
src/views/questionDetail/index.vue
View file @
3a7882f6
...
...
@@ -300,10 +300,17 @@
置顶回答
</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 || '顶' }}楼
</span>
<button
v-if=
"isSelfAnswer(answer)"
class=
"cursor-pointer text-red-500 text-xs leading-none"
@
click=
"handleDeleteAnswer(answer)"
>
删除
</button>
</div>
</div>
</div>
...
...
@@ -437,6 +444,7 @@ import {
addOrCanceArticlelCollect
,
addOrCancelCommentLike
,
topOrCancelTopComment
,
deleteComment
,
}
from
'@/api'
import
type
{
ArticleItemDto
,
CommentItemDto
}
from
'@/api'
import
{
usePageSearch
}
from
'@/hooks'
...
...
@@ -448,6 +456,7 @@ import dayjs from 'dayjs'
import
{
useUserStore
}
from
'@/stores/user'
import
{
storeToRefs
}
from
'pinia'
import
{
useNavigation
,
useScrollTop
}
from
'@/hooks'
import
{
useMessageBox
}
from
'@/hooks'
import
{
parseEmoji
}
from
'@/utils/emoji'
import
{
ArticleTypeEnum
,
BooleanFlag
}
from
'@/constants'
import
{
push
}
from
'notivue'
...
...
@@ -456,6 +465,7 @@ import { CommentSortTypeEnum } from '@/constants'
const
userStore
=
useUserStore
()
const
{
userInfo
}
=
storeToRefs
(
userStore
)
const
{
jumpToUserHomePage
}
=
useNavigation
()
const
{
confirm
}
=
useMessageBox
()
const
route
=
useRoute
()
const
router
=
useRouter
()
...
...
@@ -471,6 +481,8 @@ const sendMessageDialogRef = useTemplateRef<InstanceType<typeof SendMessageDialo
// 回滚到子评论框
const
{
handleBackTop
:
handleBackTopChildren
}
=
useScrollTop
(
answerRefList
)
const
loading
=
computed
(()
=>
!
questionDetail
.
value
.
title
)
const
isSelfAnswer
=
(
answer
:
CommentItemDto
)
=>
String
(
answer
.
userId
||
''
)
===
String
(
userInfo
.
value
.
userId
||
''
)
const
isAuthor
=
computed
(()
=>
{
return
questionDetail
.
value
.
createUserId
===
userInfo
.
value
.
userId
...
...
@@ -543,6 +555,17 @@ const handleLikeAnswer = async (answer: CommentItemDto) => {
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
highlightCommentId
=
ref
<
number
|
null
>
(
null
)
const
handleTopAnswer
=
async
(
answer
:
CommentItemDto
)
=>
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment