Commit 5051b4c6 by lijiabin

【需求 17679】 feat: 完成评论 子评论相关内容

parent 45657088
......@@ -256,7 +256,7 @@ export interface CommentSearchParams extends PageSearchParams {
* 获取子评论列表
*/
export interface CommentChildrenSearchParams extends PageSearchParams {
pId: number | string
pid: number | string
articleId: number | string
}
......@@ -293,4 +293,8 @@ export interface CommentItemDto {
userId: number
isHaveChildren: BooleanFlag
childrenNum: number
showChilderenPage: boolean
childrenPageCurrent: number
childrenPageList: CommentItemDto[]
loadingChildren: boolean
}
......@@ -93,7 +93,7 @@
<!-- 评论列表 -->
<div v-loading="loading" class="divide-y divide-gray-100" v-if="list.length">
<div v-for="item in list" :key="item.id">
<div ref="commentItemRef" v-for="item in list" :key="item.id">
<div class="p-4 transition-colors">
<div class="flex gap-3">
<img :src="item.avatar" alt="" class="w-10 h-10 rounded-full object-cover" />
......@@ -108,26 +108,23 @@
<!-- <span class="px-2 py-0.5 text-xs bg-red-100 text-red-600 rounded-full">置顶</span> -->
</div>
<!-- 换行 -->
<p class="text-gray-700 mb-3 break-all">
<p class="text-gray-700 my-2 break-all">
{{ item.content }}
</p>
<div class="flex items-center justify-between">
<div class="flex items-center gap-4 text-sm text-gray-500">
<div class="flex items-center gap-8 text-sm text-gray-500">
<span>{{ dayjs(item.createTime * 1000).format('YYYY-MM-DD HH:mm:ss') }}</span>
<!-- <button class="flex items-center gap-1 hover:text-red-500 transition-colors"> -->
<div class="flex gap-2 items-center hover:text-blue-500">
<div
class="flex items-center gap-1 cursor-pointer"
@click="handleLickComment(item)"
>
<el-icon
:size="16"
:style="{ color: item.hasPraise ? '#409eff' : '#606266' }"
>
<Pointer />
<el-icon :size="16">
<svg-icon :name="item.hasPraise ? 'praise_fill' : 'praise'"></svg-icon>
</el-icon>
<span>{{ item.postPriseCount }}</span>
</div>
<!-- </button> -->
</div>
<button
class="cursor-pointer hover:text-blue-500 transition-colors"
@click="handleReply(item)"
......@@ -138,10 +135,12 @@
</div>
<!-- 回复列表 -->
<div v-if="item.children?.length" class="mt-3 ml-4 space-y-3">
<!-- 回复评论的内容 里面可能是 展示全部的 也有可能是展示5条之内容 -->
<div
v-for="child in item.children"
v-for="child in getCurrentChildrenList(item)"
v-loading="item.loadingChildren"
:key="child.id"
class="flex gap-2 p-3 bg-gray-50 rounded-lg"
class="flex gap-2 p-3 rounded-lg"
>
<img :src="child.avatar" alt="" class="w-8 h-8 rounded-full object-cover" />
<div class="flex-1">
......@@ -150,7 +149,7 @@
>{{ child.replyUser }} 回复 @{{ child.replyName }}</span
>
</div>
<p class="text-gray-700">
<p class="text-gray-700 my-2 break-all">
{{ child.content }}
</p>
<div class="flex items-center justify-between">
......@@ -158,18 +157,19 @@
<span>{{
dayjs(child.createTime * 1000).format('YYYY-MM-DD HH:mm:ss')
}}</span>
<div class="flex gap-2 items-center hover:text-blue-500">
<div
class="flex items-center gap-1 cursor-pointer"
@click="handleLickComment(child)"
>
<el-icon
:size="16"
:style="{ color: child.hasPraise ? '#409eff' : '#606266' }"
>
<Pointer />
<el-icon :size="16">
<svg-icon
:name="child.hasPraise ? 'praise_fill' : 'praise'"
></svg-icon>
</el-icon>
<span>{{ child.postPriseCount }}</span>
</div>
</div>
<button
@click="handleReply(child)"
class="cursor-pointer hover:text-blue-500 transition-colors"
......@@ -181,6 +181,38 @@
</div>
</div>
</div>
<!-- 只有大于5 才会显示这个 -->
<div class="ml-4" v-if="item.childrenNum > 5">
<!-- 展示 展开回复 -->
<button
v-show="!item.showChilderenPage"
class="cursor-pointer hover:text-blue-500 transition-colors text-sm text-gray-500"
@click="handleExpandReply(item)"
>
还有{{ item.childrenNum - 5 }}条回复,点击查看
</button>
<!-- 展示 收起回复 以及分页 -->
<div class="flex items-center gap-2" v-show="item.showChilderenPage">
<span class="text-sm text-gray-500"
>{{ Math.ceil(item.childrenNum / 10) }}</span
>
<el-pagination
:pager-count="5"
layout="pager"
v-show="item.showChilderenPage"
:current-page="item.childrenPageCurrent"
:total="item.childrenNum"
@current-change="handleChildrenCurrentChange($event, item, index)"
/>
<button
class="cursor-pointer hover:text-blue-500 transition-colors text-sm text-gray-500"
@click="handleCollapseReply(item, index)"
>
收起回复
</button>
</div>
</div>
<!-- 展示 回复评论的输入框 -->
<div v-show="showCommentBox(item)" class="flex gap-3 mt-4">
<img :src="userInfo?.avatar" alt="" class="w-10 h-10 rounded-full object-cover" />
<div class="flex-1">
......@@ -235,7 +267,7 @@
</div>
</template>
<script lang="ts" setup>
import { getCommentList, addOrCancelCommentLike, addComment } from '@/api'
import { getCommentList, addOrCancelCommentLike, addComment, getCommentChildren } from '@/api'
import { usePageSearch, useScrollTop, useHintAnimation } from '@/hooks'
import { BooleanFlag } from '@/constants'
import type { CommentItemDto } from '@/api'
......@@ -255,8 +287,11 @@ const { userInfo } = storeToRefs(userStore)
const commentRef = useTemplateRef<HTMLElement | null>('commentRef')
const commentInputRef = useTemplateRef<HTMLElement | null>('commentInputRef')
const commentItemRefList = useTemplateRef<HTMLElement[] | null>('commentItemRef')
// 回滚到评论框
const { handleBackTop } = useScrollTop(commentRef)
// 回滚到子评论框
const { handleBackTop: handleBackTopChildren } = useScrollTop(commentItemRefList)
const { triggerAnimation } = useHintAnimation(commentInputRef, {
classes: ['scale-bounce', 'highlight', 'shake-x'],
......@@ -270,6 +305,19 @@ const { list, searchParams, goToPage, loading, changePageSize, refresh } = usePa
sortType: 2,
},
defaultSize,
formatList(list: CommentItemDto[]) {
return list.map((item) => {
// 添加新的字段 是否展示分页子评论 默认是false 当前子评论分页current 以及子评论分页列表 loading效果
return {
...item,
showChildPage: false,
childrenPageCurrent: 1,
childrenPageList: [],
loadingChildren: false,
}
})
},
},
)
const handleCurrentChange = async (e: number) => {
......@@ -304,7 +352,6 @@ const handleLickComment = async (item: CommentItemDto) => {
}
const handleReply = (item: CommentItemDto) => {
console.log(item)
replyPlaceholder.value = `回复@${item.replyUser}:`
comment.value = ''
currentCommentId.value = item.id
......@@ -327,19 +374,65 @@ const handleMyComment = async () => {
total.value++
}
const handleComment = async () => {
console.log(comment.value)
const res = await addComment({
articleId: id,
content: comment.value,
...(currentCommentId.value ? { pid: currentCommentId.value } : {}),
})
console.log(res)
ElMessage.success('发表评论成功')
refresh()
comment.value = ''
total.value++
}
// 展开回复 获取子评论列表
const handleExpandReply = async (item: CommentItemDto) => {
item.loadingChildren = true
try {
// 获取子评论
await getCommentChildrenList(item)
} catch (error) {
console.error(error)
} finally {
item.loadingChildren = false
}
item.showChilderenPage = true
}
// 收起回复
const handleCollapseReply = (item: CommentItemDto, index: number) => {
item.showChilderenPage = false
handleBackTopChildren(index)
}
// 改变子评论的当前页数
const handleChildrenCurrentChange = (e: number, item: CommentItemDto, index: number) => {
item.childrenPageCurrent = e
getCommentChildrenList(item)
handleBackTopChildren(index)
}
// 根据页数获取子评论列表
const getCommentChildrenList = async (item: CommentItemDto) => {
const { data } = await getCommentChildren({
pid: item.id,
articleId: id,
current: item.childrenPageCurrent,
size: 10,
})
item.childrenPageList = data.list
}
// 获取当前要渲染的子列表
const getCurrentChildrenList = (item: CommentItemDto) => {
if (item.showChilderenPage) {
return item.childrenPageList
} else {
return item.children
}
}
defineExpose({
scrollToCommentBox: () => handleBackTop(),
})
......
......@@ -19,16 +19,27 @@ function ScrollTopComp(_: any, { emit }: SetupContext<Events>) {
)
}
// 顺便兼容下多个的
export const useScrollTop = (
el: MaybeRef<HTMLElement | null | Window>,
el: MaybeRef<HTMLElement | null | Window | HTMLElement[] | [Window]>,
options: { compatFixedHeader?: boolean } = {},
) => {
const { compatFixedHeader = true } = options
const handleBackTop = () => {
const dom = unref(el)
if (!dom) return
const handleBackTop = (currentIndex: number = 0) => {
const initDoms = unref(el)
if (!initDoms) return
let doms = []
if (!Array.isArray(initDoms)) {
doms = [initDoms]
} else {
doms = initDoms
}
const dom = doms[currentIndex] as HTMLElement | Window
if (dom instanceof Window) {
window.scrollTo({
top: 0,
......@@ -38,13 +49,13 @@ export const useScrollTop = (
}
if (compatFixedHeader) {
const top = dom.getBoundingClientRect().top + window.scrollY - 52
const top = dom?.getBoundingClientRect?.().top + window.scrollY - 52
window.scrollTo({
top,
behavior: 'smooth',
})
} else {
dom.scrollIntoView({
dom?.scrollIntoView?.({
behavior: 'smooth',
block: 'start',
})
......
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