Commit 9662ea89 by lijiabin

【需求 17679】 perf: 继续优化

parent 1a8cb204
......@@ -335,7 +335,7 @@ export const getSecondCommentChildren = (data: {
articleId: number
}) => {
return service.request<BackendServicePageResult<CommentItemDto>>({
url: `/api/cultureComment/comment/children`,
url: `/api/cultureComment/getAllComment`,
method: 'POST',
data,
})
......
......@@ -178,6 +178,7 @@ export interface ArticleItemDto {
type: ArticleTypeEnum
userId: string
viewCount: number
childNum: number
}
}
......
......@@ -298,11 +298,13 @@
<el-pagination
v-model:current-page="searchParams.current"
v-model:page-size="searchParams.size"
:total="total"
:total="firstComentTotal"
@current-change="handleCurrentChange"
@size-change="changePageSize"
layout="prev, pager, next, total"
/>
layout="prev, pager, next, slot"
>
<div>共 {{ total }} 条</div>
</el-pagination>
</div>
</div>
</div>
......@@ -318,7 +320,7 @@ import {
getCommentChildren,
getSecondCommentList,
} from '@/api'
import { usePageSearch, useScrollTop, useHintAnimation } from '@/hooks'
import { usePageSearch, useScrollTop } from '@/hooks'
import { BooleanFlag } from '@/constants'
import type { CommentItemDto } from '@/api'
import dayjs from 'dayjs'
......@@ -333,7 +335,7 @@ const {
isQuestion = false,
commentId = 0,
} = defineProps<{
id: number
id: number // 文章ID
defaultSize?: number
isReal: BooleanFlag
isQuestion?: boolean // 如果是问题的话 展示有点不一样
......@@ -351,7 +353,6 @@ const total = defineModel<number>('total', { required: true, default: 0 })
const userStore = useUserStore()
const { userInfo } = storeToRefs(userStore)
const userAvatar = computed(() => (isReal ? userInfo.value.avatar : userInfo.value.hiddenAvatar))
console.log(userAvatar)
const commentRef = useTemplateRef<HTMLElement | null>('commentRef')
const commentDialogRef = useTemplateRef<HTMLElement | null>('commentDialogRef')
const commentInputRef = useTemplateRef<HTMLElement | null>('commentInputRef')
......@@ -361,52 +362,52 @@ const { handleBackTop } = useScrollTop(commentRef)
// 回滚到子评论框
const { handleBackTop: handleBackTopChildren } = useScrollTop(commentItemRefList)
const { triggerAnimation } = useHintAnimation(commentInputRef, {
classes: ['scale-bounce', 'highlight', 'shake-x'],
})
const { list, searchParams, goToPage, loading, changePageSize, refresh, search } = usePageSearch(
isQuestion ? getSecondCommentList : getCommentList,
{
defaultParams: {
...(commentId
? { pid: commentId, sortType: 2 }
: {
articleId: id,
sortType: 2,
}),
},
defaultSize,
formatList(list: CommentItemDto[]) {
return list.map((item) => {
// 初始化的时候 添加新的字段 是否展示分页子评论 默认是false 当前子评论分页current 以及子评论分页列表 loading效果
console.log(commentId, 'commentId')
const {
list,
searchParams,
goToPage,
loading,
changePageSize,
refresh,
search,
total: firstComentTotal,
} = usePageSearch(isQuestion ? getSecondCommentList : getCommentList, {
defaultParams: {
...(commentId
? { pid: commentId, sortType: 2 }
: {
articleId: id,
sortType: 2,
}),
},
defaultSize,
formatList(list: CommentItemDto[]) {
return list.map((item) => {
// 初始化的时候 添加新的字段 是否展示分页子评论 默认是false 当前子评论分页current 以及子评论分页列表 loading效果
const obj: CommentItemDto = { ...item }
// if (obj.showChildrenPage == undefined) {
obj.showChildrenPage = false
// }
// if (obj.childrenPageCurrent == undefined) {
obj.childrenPageCurrent = 1
// }
// if (obj.childrenPageList == undefined) {
obj.childrenPageList = []
// }
// if (obj.loadingChildren == undefined) {
obj.loadingChildren = false
// }
const obj: CommentItemDto = { ...item }
// if (obj.showChildrenPage == undefined) {
obj.showChildrenPage = false
// }
// if (obj.childrenPageCurrent == undefined) {
obj.childrenPageCurrent = 1
// }
// if (obj.childrenPageList == undefined) {
obj.childrenPageList = []
// }
// if (obj.loadingChildren == undefined) {
obj.loadingChildren = false
// }
return obj
})
},
immediate,
return obj
})
},
)
immediate,
})
const handleCurrentChange = async (e: number) => {
await goToPage(e)
handleBackTop()
setTimeout(() => {
triggerAnimation()
}, 500)
}
// 自己发出的评论
......
......@@ -3,7 +3,7 @@
v-model="visible"
:title="dialogTitle"
width="600px"
class="comment-reply-dialog rounded-xl overflow-hidden"
class="rounded-xl overflow-hidden"
:show-close="false"
append-to-body
destroy-on-close
......@@ -168,7 +168,8 @@
<input
ref="bottomInputRef"
v-model="bottomCommentContent"
type="text"
:autosize="{ minRows: 1, maxRows: 4 }"
type="textarea"
class="bg-transparent w-full outline-none text-sm text-gray-700 placeholder-gray-400"
:placeholder="`回复 ${parentComment?.replyUser || '...'}`"
@keyup.enter="submitReply(parentComment?.id)"
......@@ -233,16 +234,14 @@ const scrollContainer = ref<HTMLElement>()
// --- Actions ---
const { list, total, search, searchParams, goToPage, changePageSize } = usePageSearch(
getSecondCommentChildren,
{
const { list, total, search, searchParams, goToPage, changePageSize, refresh, loading } =
usePageSearch(getSecondCommentChildren, {
defaultParams: {
articleId: articleId,
pid: 0,
},
immediate: false,
},
)
})
const open = async (item: CommentItemDto) => {
// const { data } = await getSecondCommentChildren({
......
......@@ -109,9 +109,10 @@
</el-button>
<!-- 回答按钮保持不变 -->
<!-- 当前最热评论的评论有几条 -->
<el-button size="small" plain @click.stop="handleComment(item, index)">
<el-icon><Edit /></el-icon>
回答
{{ item.cultureCommentListVo?.childNum || 0 }}条评论
</el-button>
<ActionMore class="ml-4" :articleDetail="item" />
......@@ -121,13 +122,13 @@
<!-- 右侧:统计信息 -->
<div class="flex items-center">
<!-- 浏览量 -->
<el-button text class="flex items-center gap-2 text-gray-500">
<!-- <el-button text class="flex items-center gap-2 text-gray-500">
<el-icon><View /></el-icon>
<span class="text-sm">{{ item.viewCount || 0 }}</span>
</el-button>
</el-button> -->
<!-- 收藏 -->
<el-button
<!-- <el-button
text
class="flex items-center gap-2 text-gray-500 transition-colors"
@click.stop="handleCollect(item)"
......@@ -136,17 +137,17 @@
<span class="text-sm" :class="{ 'text-blue-500': item.hasCollect }">{{
item.collectionCount || 0
}}</span>
</el-button>
</el-button> -->
<!-- 评论 -->
<el-button
<!-- <el-button
text
class="flex items-center gap-2 text-gray-500 transition-colors"
@click.stop="handleComment(item, index)"
>
<el-icon><ChatDotRound /></el-icon>
<span class="text-sm">{{ item.replyCount || 0 }}</span>
</el-button>
<span class="text-sm">{{ item.cultureCommentListVo?.childNum || 0 }}</span>
</el-button> -->
</div>
</div>
<Transition name="fade">
......@@ -154,7 +155,7 @@
v-show="item.showComment"
:ref="(e) => (commentRefList[index] = e as InstanceType<typeof Comment>)"
:id="item.id"
:total="item.replyCount"
:total="item.cultureCommentListVo?.childNum || 0"
:defaultSize="5"
:isReal="0"
:immediate="false"
......@@ -211,19 +212,14 @@
<script setup lang="ts">
import Tabs from '@/components/common/Tabs'
import { Star, View, ChatDotRound, Refresh } from '@element-plus/icons-vue'
import { Refresh } from '@element-plus/icons-vue'
import Comment from '@/components/common/Comment/index.vue'
import { useScrollTop, usePageSearch } from '@/hooks'
import { TABS_REF_KEY } from '@/constants'
import PublishBox from '@/components/common/PublishBox/index.vue'
import { ArticleTypeEnum } from '@/constants'
import dayjs from 'dayjs'
import {
getArticleList,
addOrCanceArticlelCollect,
addOrCancelToAnswerList,
getSecondCommentList,
} from '@/api'
import { getArticleList, addOrCanceArticlelCollect, addOrCancelToAnswerList } from '@/api'
import type { ArticleItemDto } from '@/api/article/types'
import { useQuestionStore } from '@/stores/question'
import ActionMore from '@/components/common/ActionMore/index.vue'
......@@ -271,7 +267,7 @@ const handleComment = (item: ArticleItemDto, index: number) => {
}
const handleCommentSuccess = (item: ArticleItemDto) => {
item.replyCount++
item.cultureCommentListVo.childNum++
// 同时更新下
// 如果已经添加了回答 则改为未添加 并且更新问题数量
if (item.hasAddQuestion) {
......
......@@ -6,18 +6,26 @@
<!-- 标签导航 -->
<div class="bg-white p-4 mb-6 rounded-lg shadow-sm">
<div class="flex flex-wrap gap-2 mb-2">
<el-tag v-for="tag in filterOptions" :key="tag.id"
<el-tag
v-for="tag in filterOptions"
:key="tag.id"
:type="tag.id === searchParams.sortLogic ? 'primary' : 'info'"
:effect="tag.id === searchParams.sortLogic ? 'dark' : 'plain'" class="cursor-pointer"
@click="toggleFilter(tag.id)">
:effect="tag.id === searchParams.sortLogic ? 'dark' : 'plain'"
class="cursor-pointer"
@click="toggleFilter(tag.id)"
>
{{ tag.title }}
</el-tag>
</div>
<div class="flex flex-wrap gap-2">
<el-tag v-for="tag in tagList" :key="tag.id"
<el-tag
v-for="tag in tagList"
:key="tag.id"
:type="searchParams.tagIdList?.includes(tag.id) ? 'primary' : 'info'"
:effect="searchParams.tagIdList?.includes(tag.id) ? 'dark' : 'plain'" class="cursor-pointer"
@click="toggleTag(tag.id)">
:effect="searchParams.tagIdList?.includes(tag.id) ? 'dark' : 'plain'"
class="cursor-pointer"
@click="toggleTag(tag.id)"
>
{{ tag.title }}
</el-tag>
</div>
......@@ -33,40 +41,51 @@
{{ filterText }}
</h2>
</div>
<div class="text-#999 cursor-pointer text-sm" @click="
router.push({
path: '/searchPage',
query: {
type: ArticleTypeEnum.PRACTICE,
},
})
">
<div
class="text-#999 cursor-pointer text-sm"
@click="
router.push({
path: '/searchPage',
query: {
type: ArticleTypeEnum.PRACTICE,
},
})
"
>
查看更多 >>
</div>
</div>
<div class="divide-y bg-#fff">
<div @click="openArticleDetail(item.id)" v-for="item in list" :key="item.id"
class="p-4 hover:bg-gray-50 transition-colors cursor-pointer pl-8" >
<div class="flex gap-3 items-center h-100%" style="border-bottom: 1.5px solid #ddd;">
<div
@click="openArticleDetail(item.id)"
v-for="item in list"
:key="item.id"
class="p-4 hover:bg-gray-50 transition-colors cursor-pointer pl-8"
>
<div class="flex gap-3 items-center h-100%" style="border-bottom: 1.5px solid #ddd">
<!-- 左侧内容 -->
<div class="flex-1">
<h1 class="font-medium text-gray-900 mb-2 leading-relaxed line-clamp-1 text-18px">
<h1 class="font-medium text-gray-900 mb-2 leading-relaxed line-clamp-1 text-lg">
{{ item.title }}
</h1>
<!-- 带图片的内容 -->
<div class="flex gap-3 mb-3 align-center" style="border-right: 1.5px solid #ddd;">
<img v-if="item.faceUrl" :src="item.faceUrl" :alt="item.title"
class="w-40 h-25 object-cover rounded-lg flex-shrink-0" />
<div class="flex gap-3 mb-2 align-center">
<img
v-if="item.faceUrl"
:src="item.faceUrl"
:alt="item.title"
class="w-40 h-25 object-cover rounded-lg flex-shrink-0"
/>
<div class="flex-1 mr-4">
<div class="text-gray-600 text-sm leading-relaxed line-clamp-4">
<div class="text-gray-600 text-base leading-relaxed line-clamp-4">
{{ item.content }}
</div>
</div>
</div>
<!-- 互动数据 -->
<div class="flex items-center gap-5 text-gray-400 text-base mb-3">
<div class="flex items-center gap-5 text-gray-400 text-sm mb-2">
<div class="flex items-center gap-1">
<el-icon class="text-sm">
<View />
......@@ -111,14 +130,23 @@
<!-- 右侧:分页器 -->
<div class="right">
<div class="pagination-wrapper bg-white rounded-lg shadow-sm border border-gray-100 p-3">
<el-pagination v-model:current-page="searchParams.current" v-model:page-size="searchParams.size"
:page-sizes="[5, 20, 1]" layout="prev, pager, next, jumper, total" :total="total"
class="custom-pagination" @current-change="
<div
class="pagination-wrapper bg-white rounded-lg shadow-sm border border-gray-100 p-3"
>
<el-pagination
v-model:current-page="searchParams.current"
v-model:page-size="searchParams.size"
:page-sizes="[5, 20, 1]"
layout="prev, pager, next, jumper, total"
:total="total"
class="custom-pagination"
@current-change="
(e) => {
; (handleBackTop(), goToPage(e))
;(handleBackTop(), goToPage(e))
}
" @size-change="changePageSize" />
"
@size-change="changePageSize"
/>
</div>
</div>
</div>
......
<template>
<div class="min-h-screen p-6 font-sans text-gray-800 flex justify-center">
<!--
背景调整:bg-[#f9fafb]
这是一种极接近白色的淡灰,视觉上非常干净,
但能保证卡片的白色阴影依然可见。
-->
<div class="w-full max-w-4xl space-y-4">
<div class="min-h-screen pb-10 font-sans text-slate-800 flex justify-center">
<div class="w-full max-w-[1000px] space-y-4">
<!-- 1. 问题卡片 -->
<!-- 圆角调整:rounded-xl (12px),这是最标准的圆角大小 -->
<div class="bg-white rounded-xl p-8 shadow-sm border border-gray-100">
<!-- 标签 -->
<div class="flex gap-2 mb-4">
<el-tag
v-for="tag in tags"
:key="tag.id"
class="!border-none !bg-blue-50 !text-blue-600 !px-3 !h-7 !text-xs font-bold rounded-md"
<div
class="bg-white rounded-lg p-6 shadow-[0_1px_3px_rgba(0,0,0,0.02)] border border-slate-100"
>
<!-- 顶部标签行 -->
<div class="flex flex-wrap gap-2 mb-4">
<span
v-for="tag in questionDetail.tagNameList"
:key="tag"
class="px-2.5 py-0.5 rounded-full bg-blue-50 text-blue-500 text-xs font-semibold hover:bg-blue-100 transition-colors cursor-pointer"
>
{{ tag.name }}
</el-tag>
#{{ tag }}
</span>
</div>
<!-- 标题 -->
<h1 class="text-2xl font-bold text-gray-900 mb-3 leading-snug">
<!-- 标题:主要信息,黑重粗 -->
<h1 class="text-2xl font-bold text-slate-900 mb-3 leading-snug tracking-tight">
{{ questionDetail.title }}
</h1>
<!-- 描述 -->
<p class="text-gray-600 leading-relaxed mb-6 text-sm md:text-base">
{{ questionDetail.description }}
<span class="text-blue-600 cursor-pointer hover:underline text-sm font-medium ml-1"
>显示全部</span
<!-- 描述:次要信息,深灰 -->
<div class="text-slate-700 leading-relaxed text-[15px] mb-6">
<span :class="{ 'line-clamp-3': !isExpandDesc }">
{{ questionDetail.content }}
</span>
<button
v-if="questionDetail.content && questionDetail.content.length > 100"
class="text-blue-500 text-sm font-medium hover:text-blue-600 mt-1 flex items-center gap-0.5"
@click="isExpandDesc = !isExpandDesc"
>
</p>
{{ isExpandDesc ? '收起' : '显示全部' }}
<el-icon :class="{ 'rotate-180': isExpandDesc }" class="transition-transform"
><CaretBottom
/></el-icon>
</button>
</div>
<!-- 操作栏 -->
<div class="flex flex-wrap items-center justify-between gap-4 pt-2">
<!-- 底部操作栏 -->
<div class="flex items-center justify-between mt-4">
<div class="flex gap-3">
<el-button
type="primary"
class="!rounded-lg !px-5 !h-9 !text-sm !font-medium !bg-blue-600 !border-blue-600 hover:!bg-blue-700 hover:!shadow-md transition-all"
@click="isFollowing = !isFollowing"
>
{{ isFollowing ? '已关注' : '关注问题' }}
</el-button>
<el-button
class="!rounded-lg !px-5 !h-9 !text-sm !font-medium !text-blue-600 !border-blue-200 !bg-blue-50 hover:!bg-blue-100 transition-colors"
<button
class="px-5 py-1.5 border border-blue-500 text-blue-500 hover:bg-blue-50 rounded-[4px] text-sm font-medium transition-colors flex items-center gap-1 cursor-pointer"
>
<el-icon class="mr-1"><Plus /></el-icon>
<el-icon><EditPen /></el-icon>
写回答
</el-button>
<el-button
class="!rounded-lg !h-9 !px-4 !text-gray-500 hover:!text-gray-700 !bg-transparent !border-gray-200"
>
邀请回答
</el-button>
</button>
</div>
<div class="flex gap-5 text-gray-400 text-sm">
<div
class="flex items-center gap-1 cursor-pointer hover:text-gray-600 transition-colors"
<!-- 右侧数据 -->
<div class="flex items-center gap-6 text-slate-400 text-sm select-none">
<span
@click="handleLikeArticle"
class="hover:text-slate-600 cursor-pointer transition-colors flex items-center gap-1"
>
<el-icon class="text-base"><ChatDotRound /></el-icon>
<span>2 条评论</span>
</div>
<div
class="flex items-center gap-1 cursor-pointer hover:text-gray-600 transition-colors"
<el-icon>
<svg-icon :name="questionDetail?.hasPraised ? 'praise_fill' : 'praise'"></svg-icon>
</el-icon>
<span :class="{ 'text-blue-500': questionDetail?.hasPraised }">{{
questionDetail?.praiseCount || 0
}}</span>
</span>
<span
@click="handleCollectArticle"
class="hover:text-slate-600 cursor-pointer transition-colors flex items-center gap-1"
>
<el-icon class="text-base"><Share /></el-icon>
<span>分享</span>
</div>
<el-icon>
<svg-icon
:name="questionDetail?.hasCollect ? 'collection_fill' : 'collection'"
></svg-icon>
</el-icon>
<span :class="{ 'text-blue-500': questionDetail?.hasCollect }">{{
questionDetail?.collectionCount || 0
}}</span>
</span>
</div>
</div>
</div>
<!-- 2. 分隔栏 -->
<div class="flex items-center justify-between px-1 py-1">
<span class="font-bold text-gray-900 text-base">105 个回答</span>
<div
class="flex items-center text-xs text-gray-500 cursor-pointer hover:text-blue-600 font-medium bg-white px-3 py-1 rounded-md shadow-sm border border-gray-100"
>
按时间排序
<el-icon class="ml-1"><CaretBottom /></el-icon>
<!-- 2. 列表控制栏 -->
<div
class="bg-white rounded-t-lg border-b border-slate-100 p-6 flex justify-between items-center shadow-sm"
>
<h3 class="font-bold text-slate-800 text-base">{{ total }} 个回答</h3>
<div class="flex text-sm text-slate-500 bg-slate-50 rounded p-0.5">
<el-radio-group
size="small"
v-model="searchParams.sortType"
@change="(val) => changeSortType(val as number)"
>
<el-radio-button label="最新" :value="2" />
<el-radio-button label="最多评论" :value="1" />
<el-radio-button label="最多点赞" :value="4" />
</el-radio-group>
<!-- <span
@click="changeSortType(2)"
class="px-3 py-0.5 rounded shadow-sm font-medium cursor-pointer"
:class="{ 'text-slate-800 bg-white': searchParams.sortType === 2 }"
>最新</span
>
<span
@click="changeSortType(1)"
class="px-3 py-0.5 rounded hover:text-slate-700 cursor-pointer transition-colors"
:class="{ 'text-slate-800 bg-white': searchParams.sortType === 1 }"
>最多评论</span
>
<span
@click="changeSortType(4)"
class="px-3 py-0.5 rounded hover:text-slate-700 cursor-pointer transition-colors"
:class="{ 'text-slate-800 bg-white': searchParams.sortType === 4 }"
>最多点赞</span
> -->
</div>
</div>
<!-- 3. 回答列表 -->
<div class="space-y-3">
<div
v-for="answer in answers"
v-for="(answer, index) in list"
:key="answer.id"
class="bg-white rounded-xl p-8 shadow-sm border border-gray-100 hover:shadow-md transition-shadow duration-200"
class="bg-white rounded-lg p-6 shadow-sm border border-slate-100 hover:border-slate-200 transition-colors"
>
<!-- 用户 -->
<div class="flex items-center mb-3">
<img :src="answer.user.avatar" class="w-9 h-9 rounded-full object-cover bg-gray-100" />
<div class="ml-3">
<div class="font-bold text-gray-900 text-sm">{{ answer.user.name }}</div>
<div class="text-xs text-gray-400 mt-0.5">{{ answer.user.bio }}</div>
<!-- 用户头 -->
<div class="flex items-center gap-3 mb-3">
<img :src="answer.avatar" class="w-9 h-9 rounded bg-slate-100 object-cover" />
<div>
<div class="font-bold text-slate-900 text-sm flex items-center gap-2">
{{ answer.hiddenName }}
<!-- 徽章示例 -->
<!-- <span
v-if="index === 0"
class="px-1.5 py-0.5 bg-yellow-50 text-yellow-600 text-[10px] rounded scale-90 origin-left"
>优秀回答</span
> -->
</div>
<div class="text-xs text-slate-400 mt-0.5 max-w-md truncate">
{{ answer.description || '暂无简介' }}
</div>
</div>
</div>
<!-- 赞同信息 -->
<div class="mb-3 text-xs text-gray-400 flex items-center">
<span class="bg-gray-50 px-2 py-0.5 rounded text-gray-500">
{{ answer.votes }} 人赞同了该回答
</span>
<!-- 赞同票数 (微小的灰色文字,增加信息密度) -->
<div class="text-xs text-slate-400 mb-2">
{{ answer.praiseCount || 0 }} 人赞同了该回答
</div>
<!-- 正文 -->
<div
class="text-gray-800 leading-7 text-sm md:text-base mb-6"
class="text-slate-800 leading-7 text-[15px] mb-4 rich-text-content"
v-html="answer.content"
></div>
<!-- 底部操作 -->
<div class="flex items-center text-sm text-gray-400 gap-5 select-none">
<!-- 赞同按钮组:稍微方正一点的圆角 -->
<div class="flex bg-blue-50/50 rounded-lg p-0.5 border border-blue-100/50">
<div class="text-xs text-slate-400 mb-4">
发布于 {{ dayjs(answer.createTime * 1000).format('YYYY-MM-DD HH:mm') }}
</div>
<!-- 底部吸附操作栏 -->
<div class="flex items-center gap-4 select-none sticky bottom-0 bg-white pt-2">
<!-- 核心交互:赞同/反对胶囊 -->
<div class="flex items-center bg-blue-50/60 rounded-[4px] overflow-hidden">
<button
class="flex items-center px-3 py-1 rounded-md bg-white text-blue-600 shadow-sm text-xs font-bold hover:text-blue-700 transition-colors"
class="flex items-center gap-1 px-3 py-1.5 text-blue-500 hover:bg-blue-100 transition-colors text-sm font-medium cursor-pointer"
:class="{ '!bg-blue-500 !text-white': answer.hasPraise }"
@click="handleLikeAnswer(answer)"
>
<el-icon class="mr-1"><CaretTop /></el-icon>
赞同 {{ answer.votes }}
<el-icon><CaretTop /></el-icon>
<span
>{{ answer.hasPraise ? '已赞同' : '赞同' }} {{ answer.praiseCount || '' }}</span
>
</button>
<button
class="flex items-center px-2 py-1 text-blue-400 hover:text-blue-600 transition-colors ml-0.5"
<!-- <button
class="px-2 py-1.5 text-blue-600 hover:bg-blue-100 transition-colors border-l border-blue-100/50"
>
<el-icon><CaretBottom /></el-icon>
</button>
</div>
<div
class="flex items-center gap-1 cursor-pointer hover:text-gray-600 transition-colors"
>
<el-icon class="text-base"><ChatDotRound /></el-icon>
<span v-if="answer.commentCount" class="text-xs"
>{{ answer.commentCount }} 条评论</span
>
<span v-else class="text-xs">添加评论</span>
</button> -->
</div>
<div
class="flex items-center gap-1 cursor-pointer hover:text-gray-600 transition-colors"
<button
class="flex items-center gap-1.5 text-slate-500 hover:text-slate-800 transition-colors text-sm cursor-pointer"
@click="handleComment(answer, index)"
>
<el-icon class="text-base"><Share /></el-icon>
<span class="text-xs">分享</span>
</div>
<el-icon class="text-base"><ChatRound /></el-icon>
<span :class="{ 'text-slate-800 font-medium': answer.showComment }">
{{ answer.childrenNum ? `${answer.childrenNum} 条评论` : '添加评论' }}
</span>
</button>
</div>
<!-- 内嵌评论区 -->
<!-- 增加一个边框和浅灰色背景,让它看起来像一个“容器” -->
<Transition name="fade">
<div
class="flex items-center gap-1 cursor-pointer hover:text-gray-600 transition-colors"
v-show="answer.showComment"
class="mt-4 border border-slate-200 rounded-lg bg-slate-50/50 overflow-hidden"
>
<el-icon class="text-base"><Star /></el-icon>
<span class="text-xs">收藏</span>
<Comment
:ref="(e) => (commentRefList[index] = e as InstanceType<typeof Comment>)"
:id="questionId"
:total="answer.childrenNum"
:defaultSize="5"
:isReal="0"
:immediate="false"
:isQuestion="true"
:commentId="answer.id"
@commentSuccess="() => handleCommentSuccess(answer)"
/>
</div>
<span class="ml-auto text-xs text-gray-300 hidden sm:block">
{{ answer.publishDate }}
</span>
</div>
</Transition>
</div>
</div>
<!-- 底部加载更多 -->
<div class="py-3 flex justify-center bg-#fff">
<el-pagination
v-model:current-page="searchParams.current"
v-model:page-size="searchParams.size"
:total="total"
layout="prev, pager, next,total"
background
small
@current-change="goToPage"
/>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { getArticleDetail } from '@/api/article'
import type { ArticleItemDto } from '@/api/article/types'
import {
getArticleDetail,
getCommentList,
addOrCanceArticlelLike,
addOrCanceArticlelCollect,
addOrCancelCommentLike,
} from '@/api'
import type { ArticleItemDto } from '@/api/types'
import { usePageSearch } from '@/hooks'
import Comment from '@/components/common/Comment/index.vue'
import dayjs from 'dayjs'
const route = useRoute()
const questionId = route.params.id as string
const questionId = Number(route.params.id)
const commentRefList = ref<InstanceType<typeof Comment>[]>([])
const questionDetail = ref<ArticleItemDto>({} as ArticleItemDto)
const getQuestionDetail = async () => {
const res = await getArticleDetail(questionId)
console.log(res)
const { data } = await getArticleDetail(questionId)
questionDetail.value = data
console.log(questionDetail.value)
}
const { list, total, searchParams, goToPage, refresh } = usePageSearch(getCommentList, {
// immediate: false,
defaultParams: {
articleId: questionId,
sortType: 1,
},
formatList: (list) =>
list.map((item) => ({
...item,
showComment: false,
isExpand: false,
})),
})
const changeSortType = (type: number) => {
searchParams.value.sortType = type
refresh()
}
const handleLikeArticle = async () => {
await addOrCanceArticlelLike(questionId)
questionDetail.value.hasPraised = !questionDetail.value.hasPraised
questionDetail.value.praiseCount = questionDetail.value.hasPraised
? questionDetail.value.praiseCount + 1
: questionDetail.value.praiseCount - 1
ElMessage.success(`${questionDetail.value.hasPraised ? '点赞成功' : '取消点赞成功'}`)
}
const handleCollectArticle = async () => {
await addOrCanceArticlelCollect(questionId)
questionDetail.value.hasCollect = !questionDetail.value.hasCollect
questionDetail.value.collectionCount = questionDetail.value.hasCollect
? questionDetail.value.collectionCount + 1
: questionDetail.value.collectionCount - 1
ElMessage.success(`${questionDetail.value.hasCollect ? '收藏成功' : '取消收藏成功'}`)
}
const handleLikeAnswer = async (answer: any) => {
await addOrCancelCommentLike(answer.id)
ElMessage.success(`${answer.hasPraise ? '点赞成功' : '取消点赞成功'}`)
answer.hasPraise = !answer.hasPraise
answer.praiseCount = answer.hasPraise ? answer.praiseCount + 1 : answer.praiseCount - 1
}
const handleComment = (answer: any, index: number) => {
commentRefList.value[index]?.search()
answer.showComment = !answer.showComment
}
getQuestionDetail()
onMounted(() => {
getQuestionDetail()
})
</script>
<style scoped></style>
<style lang="scss" scoped>
.fade-enter-from,
.fade-leave-to {
opacity: 0;
transform: translateY(-10px);
filter: blur(4px);
}
.fade-enter-active,
.fade-leave-active {
transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
</style>
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