Commit 82eec017 by lijiabin

【需求 17679】 feat: 完成在线计时、优化评论等功能

parent 5051b4c6
...@@ -293,7 +293,7 @@ export interface CommentItemDto { ...@@ -293,7 +293,7 @@ export interface CommentItemDto {
userId: number userId: number
isHaveChildren: BooleanFlag isHaveChildren: BooleanFlag
childrenNum: number childrenNum: number
showChilderenPage: boolean showChildrenPage: boolean
childrenPageCurrent: number childrenPageCurrent: number
childrenPageList: CommentItemDto[] childrenPageList: CommentItemDto[]
loadingChildren: boolean loadingChildren: boolean
......
...@@ -14,6 +14,7 @@ export * from './practice' ...@@ -14,6 +14,7 @@ export * from './practice'
export * from './common' export * from './common'
export * from './login' export * from './login'
export * from './article' export * from './article'
export * from './online'
// 导出类型 // 导出类型
export * from './task/types' export * from './task/types'
export * from './shop/types' export * from './shop/types'
...@@ -29,3 +30,4 @@ export * from './practice/types' ...@@ -29,3 +30,4 @@ export * from './practice/types'
export * from './common/types' export * from './common/types'
export * from './login/types' export * from './login/types'
export * from './article/types' export * from './article/types'
export * from './online/types'
import service from '@/utils/request/index'
// import type {
// AddOrUpdateArticleDto,
// ArticleItemDto,
// ArticleSearchParams,
// InterviewOptionDto,
// ColumnOptionDto,
// AddCommentDto,
// CommentItemDto,
// CommentSearchParams,
// InterviewItemDto,
// ColumnItemDto,
// VideoOptionDto,
// CommentChildrenSearchParams,
// } from './types'
// import type { BackendServicePageResult, PageSearchParams } from '@/utils/request/types'
// 在线时长的功能
/**
* 获取当前用户在线时长
*/
export const getTodayOnlineSeconds = () => {
return service.request<number>({
url: '/api/personalCenter/getTodayOnlineSeconds',
method: 'POST',
// data: {},
})
}
/**
* 暂时这种轮询方案 30s调一次
*/
export const heartbeat = () => {
return service.request<boolean>({
url: '/api/personalCenter/heartbeat',
method: 'POST',
data: {},
})
}
import { ArticleTypeEnum, ReleaseStatusTypeEnum, BooleanFlag, SendTypeEnum } from '@/constants'
import type { PageSearchParams } from '@/utils/request/types'
/**
* 搜索文章的参数
*/
export interface ArticleSearchParams extends PageSearchParams {
type?: ArticleTypeEnum
sortLogic?: number
title?: string
}
/**
* 添加或更新文章DTO(带枚举版本)
*/
export type AddOrUpdateArticleDto =
| AddOrUpdatePostDto
| AddOrUpdateColumnDto
| AddOrUpdateInterviewDto
| AddOrUpdateVideoDto
/**
* 添加帖子的DTO
*/
export interface AddOrUpdatePostDto {
id?: number
title?: string
content?: string
releaseStatus?: ReleaseStatusTypeEnum
sendType?: SendTypeEnum
faceUrl?: string
imgUrl?: string
sendTime?: string
type?: ArticleTypeEnum.POST
}
interface AddOrUpdateColumnBase {
id?: number
type: ArticleTypeEnum.COLUMN
title: string
content: string
releaseStatus: ReleaseStatusTypeEnum
sendType: SendTypeEnum
faceUrl?: string
imgUrl?: string
// 关联的专栏栏目
relateColumnId?: number
mainTagId: string
isRelateColleague: BooleanFlag
sendTime?: string
isRecommend: BooleanFlag
}
/**
* 添加专栏的原始form类型
*/
export interface AddOrUpdateColumnForm extends AddOrUpdateColumnBase {
tagList: number[]
}
/**
* 添加专栏的DTO
*/
export interface AddOrUpdateColumnDto extends AddOrUpdateColumnBase {
tagList: { tagId: number; sort: number }[]
}
export interface AddOrUpdateInterviewBase {
id?: number
type: ArticleTypeEnum.INTERVIEW
title: string
content: string
releaseStatus: ReleaseStatusTypeEnum
sendType: SendTypeEnum
faceUrl?: string
imgUrl?: string
// 关联的专访栏目
relateColumnId?: number
mainTagId: string
sendTime?: string
isRecommend: BooleanFlag
}
export interface AddOrUpdateInterviewForm extends AddOrUpdateInterviewBase {
tagList: number[]
}
/**
* 添加专访的DTO
*/
export interface AddOrUpdateInterviewDto extends AddOrUpdateInterviewBase {
tagList: { tagId: number; sort: number }[]
}
export interface AddOrUpdateVideoDto {
id?: number
title: string
type: ArticleTypeEnum.VIDEO
content: string
videoUrl: string
videoDuration: string
releaseStatus: ReleaseStatusTypeEnum
sendType: SendTypeEnum
faceUrl?: string
imgUrl?: string
sendTime?: string
isRecommend?: BooleanFlag
mainTagId: string | number
tagList: { tagId: number; sort: number }[] | number[]
relateColumnId?: number
}
/**
* 添加专访的DTO
*/
/**
* 文章详情
*/
export interface ArticleItemDto {
id: number
title: string
content: string
faceUrl: string
videoUrl: string
description: string
createUserId: number
createTime: number
viewCount: number
isRecommend: BooleanFlag
type: ArticleTypeEnum
isRelateColleague: BooleanFlag
releaseStatus: ReleaseStatusTypeEnum
tagNameList: string[]
praiseCount: number
collectionCount: number
replyCount: number
hasPraised: boolean
hasCollect: boolean
imgUrl: string
createUserAvatar: string
createUserName: string
showAvatar: string
showName: string
videoDuration: string
showComment?: boolean
relateColumn?: string
rewardNum: number
}
/**
* 专栏选项
*/
export interface ColumnOptionDto {
color: string
createTime: number
createUserId: number
id: number
isDelete: BooleanFlag
sort: number
status: BooleanFlag
title: string
type: 'column'
}
/**
* 专栏列表Item
*/
export interface ColumnItemDto {
title: string
color: string
sort: number
yaColumnVoList: {
articleId: number
collectCount: number
content: string
createTime: number
description: string
faceUrl: string
hasPraised: boolean
isRecommend: number
praiseCount: number
replyCount: number
title: string
type: ArticleTypeEnum.COLUMN
viewCount: number
}[]
}
/**
* 专访选项
*/
export interface InterviewOptionDto {
color: string
createTime: number
createUserId: number
id: number
isDelete: BooleanFlag
sort: number
status: BooleanFlag
title: string
type: 'column'
}
/**
* 视频选项
*/
export interface VideoOptionDto {
color: string
createTime: number
createUserId: number
id: number
isDelete: BooleanFlag
sort: number
status: BooleanFlag
title: string
type: 'video'
}
/**
* 专访列表Item
*/
export interface InterviewItemDto {
title: string
color: string
sort: number
yaColumnVoList: {
articleId: number
collectCount: number
content: string
createTime: number
description: string
faceUrl: string
hasPraised: boolean
isRecommend: number
praiseCount: number
replyCount: number
title: string
type: ArticleTypeEnum.INTERVIEW
viewCount: number
}[]
}
/**
* 视频选项
*/
/**
* 评论列表
*/
export interface CommentSearchParams extends PageSearchParams {
articleId: number | string
sortType: number
}
/**
* 获取子评论列表
*/
export interface CommentChildrenSearchParams extends PageSearchParams {
pid: number | string
articleId: number | string
}
/**
* 新增评论
*/
export interface AddCommentDto {
articleId: number | string
content: string
pId?: number | string
}
/**
* 评论信息
*/
export interface CommentItemDto {
articleId: number
avatar: string
children: CommentItemDto[]
content: string
createTime: number
hasPraise: BooleanFlag
hiddenAvatar: string
hiddenName: string
id: number
isFeatured: number
isTop: number
pid: number
postPriseCount: number
region: string
regionHide: number
replyUser: string
replyName: string
userId: number
isHaveChildren: BooleanFlag
childrenNum: number
showChildrenPage: boolean
childrenPageCurrent: number
childrenPageList: CommentItemDto[]
loadingChildren: boolean
}
...@@ -93,7 +93,11 @@ ...@@ -93,7 +93,11 @@
<!-- 评论列表 --> <!-- 评论列表 -->
<div v-loading="loading" class="divide-y divide-gray-100" v-if="list.length"> <div v-loading="loading" class="divide-y divide-gray-100" v-if="list.length">
<div ref="commentItemRef" v-for="item in list" :key="item.id"> <div
v-for="(item, index) in list"
:key="item.id"
:ref="(el) => (commentItemRefList[index] = el as HTMLElement)"
>
<div class="p-4 transition-colors"> <div class="p-4 transition-colors">
<div class="flex gap-3"> <div class="flex gap-3">
<img :src="item.avatar" alt="" class="w-10 h-10 rounded-full object-cover" /> <img :src="item.avatar" alt="" class="w-10 h-10 rounded-full object-cover" />
...@@ -182,24 +186,27 @@ ...@@ -182,24 +186,27 @@
</div> </div>
</div> </div>
<!-- 只有大于5 才会显示这个 --> <!-- 只有大于5 才会显示这个 -->
<div class="ml-4" v-if="item.childrenNum > 5"> <div class="ml-4" v-show="item.childrenNum > 5">
<!-- 展示 展开回复 --> <!-- 展示 展开回复 -->
<button <button
v-show="!item.showChilderenPage" v-show="!item.showChildrenPage"
class="cursor-pointer hover:text-blue-500 transition-colors text-sm text-gray-500" class="cursor-pointer text-sm text-gray-500"
@click="handleExpandReply(item)" @click="handleExpandReply(item)"
> >
还有{{ item.childrenNum - 5 }}条回复,点击查看 还有{{ item.childrenNum - 5 }}条回复,<span
class="hover:text-blue-500 transition-colors"
>点击查看</span
>
</button> </button>
<!-- 展示 收起回复 以及分页 --> <!-- 展示 收起回复 以及分页 -->
<div class="flex items-center gap-2" v-show="item.showChilderenPage"> <div class="flex items-center gap-2" v-show="item.showChildrenPage">
<span class="text-sm text-gray-500" <span class="text-sm text-gray-500"
>{{ Math.ceil(item.childrenNum / 10) }}</span >{{ Math.ceil(item.childrenNum / 10) }}</span
> >
<el-pagination <el-pagination
:pager-count="5" :pager-count="5"
layout="pager" layout="pager"
v-show="item.showChilderenPage" v-show="item.showChildrenPage"
:current-page="item.childrenPageCurrent" :current-page="item.childrenPageCurrent"
:total="item.childrenNum" :total="item.childrenNum"
@current-change="handleChildrenCurrentChange($event, item, index)" @current-change="handleChildrenCurrentChange($event, item, index)"
...@@ -213,6 +220,7 @@ ...@@ -213,6 +220,7 @@
</div> </div>
</div> </div>
<!-- 展示 回复评论的输入框 --> <!-- 展示 回复评论的输入框 -->
<!-- <transition name="fade" mode="out-in"> -->
<div v-show="showCommentBox(item)" class="flex gap-3 mt-4"> <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" /> <img :src="userInfo?.avatar" alt="" class="w-10 h-10 rounded-full object-cover" />
<div class="flex-1"> <div class="flex-1">
...@@ -234,13 +242,14 @@ ...@@ -234,13 +242,14 @@
<button <button
class="cursor-pointer disabled:opacity-50 px-6 py-2 bg-gradient-to-r from-blue-500 to-purple-500 text-white rounded-full text-sm hover:shadow-lg transition-all" class="cursor-pointer disabled:opacity-50 px-6 py-2 bg-gradient-to-r from-blue-500 to-purple-500 text-white rounded-full text-sm hover:shadow-lg transition-all"
:disabled="!comment.trim()" :disabled="!comment.trim()"
@click="handleComment" @click="handleComment(index)"
> >
发表 发表
</button> </button>
</div> </div>
</div> </div>
</div> </div>
<!-- </transition> -->
</div> </div>
</div> </div>
</div> </div>
...@@ -287,7 +296,7 @@ const { userInfo } = storeToRefs(userStore) ...@@ -287,7 +296,7 @@ const { userInfo } = storeToRefs(userStore)
const commentRef = useTemplateRef<HTMLElement | null>('commentRef') const commentRef = useTemplateRef<HTMLElement | null>('commentRef')
const commentInputRef = useTemplateRef<HTMLElement | null>('commentInputRef') const commentInputRef = useTemplateRef<HTMLElement | null>('commentInputRef')
const commentItemRefList = useTemplateRef<HTMLElement[] | null>('commentItemRef') const commentItemRefList = ref<HTMLElement[]>([])
// 回滚到评论框 // 回滚到评论框
const { handleBackTop } = useScrollTop(commentRef) const { handleBackTop } = useScrollTop(commentRef)
// 回滚到子评论框 // 回滚到子评论框
...@@ -297,7 +306,7 @@ const { triggerAnimation } = useHintAnimation(commentInputRef, { ...@@ -297,7 +306,7 @@ const { triggerAnimation } = useHintAnimation(commentInputRef, {
classes: ['scale-bounce', 'highlight', 'shake-x'], classes: ['scale-bounce', 'highlight', 'shake-x'],
}) })
const { list, searchParams, goToPage, loading, changePageSize, refresh } = usePageSearch( const { list, searchParams, goToPage, loading, changePageSize, refresh, search } = usePageSearch(
getCommentList, getCommentList,
{ {
defaultParams: { defaultParams: {
...@@ -307,15 +316,23 @@ const { list, searchParams, goToPage, loading, changePageSize, refresh } = usePa ...@@ -307,15 +316,23 @@ const { list, searchParams, goToPage, loading, changePageSize, refresh } = usePa
defaultSize, defaultSize,
formatList(list: CommentItemDto[]) { formatList(list: CommentItemDto[]) {
return list.map((item) => { return list.map((item) => {
// 添加新的字段 是否展示分页子评论 默认是false 当前子评论分页current 以及子评论分页列表 loading效果 // 初始化的时候 添加新的字段 是否展示分页子评论 默认是false 当前子评论分页current 以及子评论分页列表 loading效果
return { const obj: CommentItemDto = { ...item }
...item, // if (obj.showChildrenPage == undefined) {
showChildPage: false, obj.showChildrenPage = false
childrenPageCurrent: 1, // }
childrenPageList: [], // if (obj.childrenPageCurrent == undefined) {
loadingChildren: false, obj.childrenPageCurrent = 1
} // }
// if (obj.childrenPageList == undefined) {
obj.childrenPageList = []
// }
// if (obj.loadingChildren == undefined) {
obj.loadingChildren = false
// }
return obj
}) })
}, },
}, },
...@@ -352,14 +369,18 @@ const handleLickComment = async (item: CommentItemDto) => { ...@@ -352,14 +369,18 @@ const handleLickComment = async (item: CommentItemDto) => {
} }
const handleReply = (item: CommentItemDto) => { const handleReply = (item: CommentItemDto) => {
console.log('回复', item)
replyPlaceholder.value = `回复@${item.replyUser}:` replyPlaceholder.value = `回复@${item.replyUser}:`
comment.value = '' comment.value = ''
currentCommentId.value = item.id currentCommentId.value = item.id
console.log(currentCommentId.value)
} }
// 是否展示子评论回复框
const showCommentBox = (item: CommentItemDto) => { const showCommentBox = (item: CommentItemDto) => {
return ( return (
currentCommentId.value === item.id || currentCommentId.value === item.id ||
item.children?.some((i) => i.id === currentCommentId.value) getCurrentChildrenList(item)?.some((i) => i.id === currentCommentId.value)
) )
} }
...@@ -373,16 +394,20 @@ const handleMyComment = async () => { ...@@ -373,16 +394,20 @@ const handleMyComment = async () => {
myComment.value = '' myComment.value = ''
total.value++ total.value++
} }
const handleComment = async () => {
const res = await addComment({ const handleComment = async (index: number) => {
await addComment({
articleId: id, articleId: id,
content: comment.value, content: comment.value,
...(currentCommentId.value ? { pid: currentCommentId.value } : {}), ...(currentCommentId.value ? { pid: currentCommentId.value } : {}),
}) })
ElMessage.success('发表评论成功') ElMessage.success('发表评论成功')
refresh()
comment.value = '' comment.value = ''
total.value++ total.value++
handleBackTopChildren(index)
// 只需要刷新当前的评论
search()
} }
// 展开回复 获取子评论列表 // 展开回复 获取子评论列表
...@@ -397,11 +422,11 @@ const handleExpandReply = async (item: CommentItemDto) => { ...@@ -397,11 +422,11 @@ const handleExpandReply = async (item: CommentItemDto) => {
item.loadingChildren = false item.loadingChildren = false
} }
item.showChilderenPage = true item.showChildrenPage = true
} }
// 收起回复 // 收起回复
const handleCollapseReply = (item: CommentItemDto, index: number) => { const handleCollapseReply = (item: CommentItemDto, index: number) => {
item.showChilderenPage = false item.showChildrenPage = false
handleBackTopChildren(index) handleBackTopChildren(index)
} }
...@@ -426,7 +451,7 @@ const getCommentChildrenList = async (item: CommentItemDto) => { ...@@ -426,7 +451,7 @@ const getCommentChildrenList = async (item: CommentItemDto) => {
// 获取当前要渲染的子列表 // 获取当前要渲染的子列表
const getCurrentChildrenList = (item: CommentItemDto) => { const getCurrentChildrenList = (item: CommentItemDto) => {
if (item.showChilderenPage) { if (item.showChildrenPage) {
return item.childrenPageList return item.childrenPageList
} else { } else {
return item.children return item.children
...@@ -437,3 +462,15 @@ defineExpose({ ...@@ -437,3 +462,15 @@ defineExpose({
scrollToCommentBox: () => handleBackTop(), scrollToCommentBox: () => handleBackTop(),
}) })
</script> </script>
<style scoped lang="scss">
.fade-enter-from,
.fade-leave-to {
opacity: 0;
transform: translateY(10px);
}
.fade-enter-active,
.fade-leave-active {
transition: all 0.3s ease;
}
</style>
...@@ -28,7 +28,6 @@ export const useScrollTop = ( ...@@ -28,7 +28,6 @@ export const useScrollTop = (
const handleBackTop = (currentIndex: number = 0) => { const handleBackTop = (currentIndex: number = 0) => {
const initDoms = unref(el) const initDoms = unref(el)
if (!initDoms) return if (!initDoms) return
let doms = [] let doms = []
......
...@@ -38,13 +38,16 @@ ...@@ -38,13 +38,16 @@
<div <div
class="text-center text-2xl font-bold bg-gradient-to-r from-blue-500 to-purple-500 bg-clip-text text-transparent" class="text-center text-2xl font-bold bg-gradient-to-r from-blue-500 to-purple-500 bg-clip-text text-transparent"
> >
00:00 {{ formatSeconds }}
</div> </div>
</div> </div>
<div class="absolute bottom-2 left-3 right-3 h-1 bg-gray-200 rounded-full overflow-hidden"> <div class="absolute bottom-2 left-3 right-3 h-1 bg-gray-200 rounded-full overflow-hidden">
<div <div
class="h-full bg-gradient-to-r from-blue-400 to-purple-400 rounded-full w-3/5 animate-pulse" class="h-full bg-gradient-to-r from-blue-400 to-purple-400 rounded-full animate-pulse"
:style="{
width: widthRate + '%',
}"
></div> ></div>
</div> </div>
...@@ -67,12 +70,49 @@ ...@@ -67,12 +70,49 @@
<script setup lang="ts"> <script setup lang="ts">
import { UseDraggable as Draggable } from '@vueuse/components' import { UseDraggable as Draggable } from '@vueuse/components'
import { useWindowSize } from '@vueuse/core' import { useWindowSize } from '@vueuse/core'
import { getTodayOnlineSeconds, heartbeat } from '@/api'
import dayjs from 'dayjs'
import utc from 'dayjs/plugin/utc'
dayjs.extend(utc)
const { width, height } = useWindowSize() const { width, height } = useWindowSize()
const CONTAINER_WIDTH = 130, const CONTAINER_WIDTH = 130,
CONTAINER_HEIGHT = 170, CONTAINER_HEIGHT = 170,
GAP = 30 GAP = 30
const maxSeconds = 60 * 30 // 半小时
const x = width.value - CONTAINER_WIDTH - GAP const x = width.value - CONTAINER_WIDTH - GAP
const y = height.value - CONTAINER_HEIGHT - GAP const y = height.value - CONTAINER_HEIGHT - GAP
const currentSeconds = ref(0)
// 进度条的比例
const widthRate = computed(() => {
if (currentSeconds.value >= maxSeconds) {
return 100
} else {
return (currentSeconds.value / maxSeconds) * 100
}
})
// 在线时长格式化 将秒级 格式化为 00:00
const formatSeconds = computed(() => {
if (currentSeconds.value >= maxSeconds) {
return '30:00'
} else {
return dayjs.utc(currentSeconds.value * 1000).format('mm:ss')
}
})
onMounted(async () => {
const { data } = await getTodayOnlineSeconds()
currentSeconds.value = parseInt(data)
})
setInterval(() => {
currentSeconds.value++
}, 1000)
setTimeout(async () => {
heartbeat()
}, 1000 * 30)
</script> </script>
...@@ -84,7 +84,7 @@ ...@@ -84,7 +84,7 @@
</div> </div>
<div class="flex-1 w-full flex items-center justify-center"> <div class="flex-1 w-full flex items-center justify-center">
<div <div
class="container max-h-none px-0 lg:px-10 2xl:px-30 transition-all duration-300 min-h-[calc(100vh-96px)]" class="container max-h-none px-0 lg:px-10 2xl:px-43 transition-all duration-300 min-h-[calc(100vh-96px)]"
> >
<router-view v-slot="{ Component, route }"> <router-view v-slot="{ Component, route }">
<transition name="fade" mode="out-in"> <transition name="fade" mode="out-in">
......
...@@ -95,7 +95,7 @@ ...@@ -95,7 +95,7 @@
<el-pagination <el-pagination
v-model:current-page="searchParams.current" v-model:current-page="searchParams.current"
v-model:page-size="searchParams.size" v-model:page-size="searchParams.size"
:page-sizes="[5, 20, 1]" :page-sizes="[5, 10, 20]"
layout="prev, pager, next, jumper, total" layout="prev, pager, next, jumper, total"
:total="total" :total="total"
class="custom-pagination" class="custom-pagination"
...@@ -134,7 +134,7 @@ const { list, total, searchParams, loading, goToPage, changePageSize, refresh } ...@@ -134,7 +134,7 @@ const { list, total, searchParams, loading, goToPage, changePageSize, refresh }
{ {
defaultParams: { sortLogic: 0 }, defaultParams: { sortLogic: 0 },
defaultCurrent: 1, defaultCurrent: 1,
defaultSize: 5, defaultSize: 8,
immediate: false, immediate: false,
}, },
) )
......
...@@ -6,18 +6,26 @@ ...@@ -6,18 +6,26 @@
<!-- 标签导航 --> <!-- 标签导航 -->
<div class="bg-white p-4 mb-6 rounded-lg shadow-sm"> <div class="bg-white p-4 mb-6 rounded-lg shadow-sm">
<div class="flex flex-wrap gap-2 mb-2"> <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'" :type="tag.id === searchParams.sortLogic ? 'primary' : 'info'"
:effect="tag.id === searchParams.sortLogic ? 'dark' : 'plain'" class="cursor-pointer" :effect="tag.id === searchParams.sortLogic ? 'dark' : 'plain'"
@click="toggleFilter(tag.id)"> class="cursor-pointer"
@click="toggleFilter(tag.id)"
>
{{ tag.title }} {{ tag.title }}
</el-tag> </el-tag>
</div> </div>
<div class="flex flex-wrap gap-2"> <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'" :type="searchParams.tagIdList?.includes(tag.id) ? 'primary' : 'info'"
:effect="searchParams.tagIdList?.includes(tag.id) ? 'dark' : 'plain'" class="cursor-pointer" :effect="searchParams.tagIdList?.includes(tag.id) ? 'dark' : 'plain'"
@click="toggleTag(tag.id)"> class="cursor-pointer"
@click="toggleTag(tag.id)"
>
{{ tag.title }} {{ tag.title }}
</el-tag> </el-tag>
</div> </div>
...@@ -33,20 +41,29 @@ ...@@ -33,20 +41,29 @@
{{ filterText }} {{ filterText }}
</h2> </h2>
</div> </div>
<div class="text-#999 cursor-pointer text-sm" @click="router.push({ <div
class="text-#999 cursor-pointer text-sm"
@click="
router.push({
path: '/searchPage', path: '/searchPage',
query: { query: {
type: ArticleTypeEnum.PRACTICE type: ArticleTypeEnum.PRACTICE,
} },
})"> })
"
>
查看更多 >> 查看更多 >>
</div> </div>
</div> </div>
<el-divider class="my-1!" /> <el-divider class="my-1!" />
<div class="divide-y bg-#fff"> <div class="divide-y bg-#fff">
<div @click="router.push(`/articleDetail/${item.id}`)" v-for="item in list" :key="item.id" <div
class="p-4 hover:bg-gray-50 transition-colors cursor-pointer"> @click="router.push(`/articleDetail/${item.id}`)"
v-for="item in list"
:key="item.id"
class="p-4 hover:bg-gray-50 transition-colors cursor-pointer"
>
<div class="flex gap-3 items-center"> <div class="flex gap-3 items-center">
<!-- 左侧内容 --> <!-- 左侧内容 -->
<div class="flex-1"> <div class="flex-1">
...@@ -56,8 +73,12 @@ ...@@ -56,8 +73,12 @@
<!-- 带图片的内容 --> <!-- 带图片的内容 -->
<div class="flex gap-3 mb-3"> <div class="flex gap-3 mb-3">
<img v-if="item.faceUrl" :src="item.faceUrl" :alt="item.title" <img
class="w-20 h-20 object-cover rounded-lg flex-shrink-0" /> v-if="item.faceUrl"
:src="item.faceUrl"
:alt="item.title"
class="w-20 h-20 object-cover rounded-lg flex-shrink-0"
/>
<div class="flex-1"> <div class="flex-1">
<div class="text-gray-600 text-sm leading-relaxed line-clamp-3"> <div class="text-gray-600 text-sm leading-relaxed line-clamp-3">
{{ item.content }} {{ item.content }}
...@@ -109,14 +130,23 @@ ...@@ -109,14 +130,23 @@
<!-- 右侧:分页器 --> <!-- 右侧:分页器 -->
<div class="right"> <div class="right">
<div class="pagination-wrapper bg-white rounded-lg shadow-sm border border-gray-100 p-3"> <div
<el-pagination v-model:current-page="searchParams.current" v-model:page-size="searchParams.size" class="pagination-wrapper bg-white rounded-lg shadow-sm border border-gray-100 p-3"
:page-sizes="[5, 20, 1]" layout="prev, pager, next, jumper, total" :total="total" >
class="custom-pagination" @current-change=" <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) => { (e) => {
; (handleBackTop(), goToPage(e)) ;(handleBackTop(), goToPage(e))
} }
" @size-change="changePageSize" /> "
@size-change="changePageSize"
/>
</div> </div>
</div> </div>
</div> </div>
...@@ -154,7 +184,7 @@ const { list, total, searchParams, goToPage, changePageSize, refresh } = usePage ...@@ -154,7 +184,7 @@ const { list, total, searchParams, goToPage, changePageSize, refresh } = usePage
{ {
defaultParams: { sortLogic: filterOptions.value[0]?.id, tagIdList: [] }, defaultParams: { sortLogic: filterOptions.value[0]?.id, tagIdList: [] },
defaultCurrent: 1, defaultCurrent: 1,
defaultSize: 5, defaultSize: 8,
immediate: false, immediate: false,
}, },
) )
......
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