Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
corporateCulture-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
王立鹏
corporateCulture-qd
Commits
82eec017
Commit
82eec017
authored
Dec 02, 2025
by
lijiabin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
【需求 17679】 feat: 完成在线计时、优化评论等功能
parent
5051b4c6
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
503 additions
and
55 deletions
+503
-55
types.ts
src/api/article/types.ts
+1
-1
index.ts
src/api/index.ts
+2
-0
index.ts
src/api/online/index.ts
+40
-0
types.ts
src/api/online/types.ts
+300
-0
index.vue
src/components/common/Comment/index.vue
+62
-25
useScrollTop.tsx
src/hooks/useScrollTop.tsx
+0
-1
onlineTime.vue
src/layoutCulture/components/onlineTime.vue
+42
-2
index.vue
src/layoutCulture/index.vue
+1
-1
recommendList.vue
src/views/homePage/homeTab/components/recommendList.vue
+2
-2
practiceList.vue
src/views/homePage/yaTab/components/practiceList.vue
+53
-23
No files found.
src/api/article/types.ts
View file @
82eec017
...
...
@@ -293,7 +293,7 @@ export interface CommentItemDto {
userId
:
number
isHaveChildren
:
BooleanFlag
childrenNum
:
number
showChild
e
renPage
:
boolean
showChildrenPage
:
boolean
childrenPageCurrent
:
number
childrenPageList
:
CommentItemDto
[]
loadingChildren
:
boolean
...
...
src/api/index.ts
View file @
82eec017
...
...
@@ -14,6 +14,7 @@ export * from './practice'
export
*
from
'./common'
export
*
from
'./login'
export
*
from
'./article'
export
*
from
'./online'
// 导出类型
export
*
from
'./task/types'
export
*
from
'./shop/types'
...
...
@@ -29,3 +30,4 @@ export * from './practice/types'
export
*
from
'./common/types'
export
*
from
'./login/types'
export
*
from
'./article/types'
export
*
from
'./online/types'
src/api/online/index.ts
0 → 100644
View file @
82eec017
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
:
{},
})
}
src/api/online/types.ts
0 → 100644
View file @
82eec017
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
}
src/components/common/Comment/index.vue
View file @
82eec017
...
...
@@ -93,7 +93,11 @@
<!-- 评论列表 -->
<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=
"flex gap-3"
>
<img
:src=
"item.avatar"
alt=
""
class=
"w-10 h-10 rounded-full object-cover"
/>
...
...
@@ -182,24 +186,27 @@
</div>
</div>
<!-- 只有大于5 才会显示这个 -->
<div
class=
"ml-4"
v-
if
=
"item.childrenNum > 5"
>
<div
class=
"ml-4"
v-
show
=
"item.childrenNum > 5"
>
<!-- 展示 展开回复 -->
<button
v-show=
"!item.showChild
e
renPage"
class=
"cursor-pointer
hover:text-blue-500 transition-colors
text-sm text-gray-500"
v-show=
"!item.showChildrenPage"
class=
"cursor-pointer text-sm text-gray-500"
@
click=
"handleExpandReply(item)"
>
还有
{{
item
.
childrenNum
-
5
}}
条回复,点击查看
还有
{{
item
.
childrenNum
-
5
}}
条回复,
<span
class=
"hover:text-blue-500 transition-colors"
>
点击查看
</span
>
</button>
<!-- 展示 收起回复 以及分页 -->
<div
class=
"flex items-center gap-2"
v-show=
"item.showChild
e
renPage"
>
<div
class=
"flex items-center gap-2"
v-show=
"item.showChildrenPage"
>
<span
class=
"text-sm text-gray-500"
>
共
{{
Math
.
ceil
(
item
.
childrenNum
/
10
)
}}
页
</span
>
<el-pagination
:pager-count=
"5"
layout=
"pager"
v-show=
"item.showChild
e
renPage"
v-show=
"item.showChildrenPage"
:current-page=
"item.childrenPageCurrent"
:total=
"item.childrenNum"
@
current-change=
"handleChildrenCurrentChange($event, item, index)"
...
...
@@ -213,6 +220,7 @@
</div>
</div>
<!-- 展示 回复评论的输入框 -->
<!--
<transition
name=
"fade"
mode=
"out-in"
>
-->
<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"
>
...
...
@@ -234,13 +242,14 @@
<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"
:disabled=
"!comment.trim()"
@
click=
"handleComment"
@
click=
"handleComment
(index)
"
>
发表
</button>
</div>
</div>
</div>
<!--
</transition>
-->
</div>
</div>
</div>
...
...
@@ -287,7 +296,7 @@ const { userInfo } = storeToRefs(userStore)
const
commentRef
=
useTemplateRef
<
HTMLElement
|
null
>
(
'commentRef'
)
const
commentInputRef
=
useTemplateRef
<
HTMLElement
|
null
>
(
'commentInputRef'
)
const
commentItemRefList
=
useTemplateRef
<
HTMLElement
[]
|
null
>
(
'commentItemRef'
)
const
commentItemRefList
=
ref
<
HTMLElement
[]
>
([]
)
// 回滚到评论框
const
{
handleBackTop
}
=
useScrollTop
(
commentRef
)
// 回滚到子评论框
...
...
@@ -297,7 +306,7 @@ const { triggerAnimation } = useHintAnimation(commentInputRef, {
classes
:
[
'scale-bounce'
,
'highlight'
,
'shake-x'
],
})
const
{
list
,
searchParams
,
goToPage
,
loading
,
changePageSize
,
refresh
}
=
usePageSearch
(
const
{
list
,
searchParams
,
goToPage
,
loading
,
changePageSize
,
refresh
,
search
}
=
usePageSearch
(
getCommentList
,
{
defaultParams
:
{
...
...
@@ -307,15 +316,23 @@ const { list, searchParams, goToPage, loading, changePageSize, refresh } = usePa
defaultSize
,
formatList
(
list
:
CommentItemDto
[])
{
return
list
.
map
((
item
)
=>
{
// 添加新的字段 是否展示分页子评论 默认是false 当前子评论分页current 以及子评论分页列表 loading效果
// 初始化的时候 添加新的字段 是否展示分页子评论 默认是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
// }
return
{
...
item
,
showChildPage
:
false
,
childrenPageCurrent
:
1
,
childrenPageList
:
[],
loadingChildren
:
false
,
}
return
obj
})
},
},
...
...
@@ -352,14 +369,18 @@ const handleLickComment = async (item: CommentItemDto) => {
}
const
handleReply
=
(
item
:
CommentItemDto
)
=>
{
console
.
log
(
'回复'
,
item
)
replyPlaceholder
.
value
=
`回复@
${
item
.
replyUser
}
:`
comment
.
value
=
''
currentCommentId
.
value
=
item
.
id
console
.
log
(
currentCommentId
.
value
)
}
// 是否展示子评论回复框
const
showCommentBox
=
(
item
:
CommentItemDto
)
=>
{
return
(
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 () => {
myComment
.
value
=
''
total
.
value
++
}
const
handleComment
=
async
()
=>
{
const
res
=
await
addComment
({
const
handleComment
=
async
(
index
:
number
)
=>
{
await
addComment
({
articleId
:
id
,
content
:
comment
.
value
,
...(
currentCommentId
.
value
?
{
pid
:
currentCommentId
.
value
}
:
{}),
})
ElMessage
.
success
(
'发表评论成功'
)
refresh
()
comment
.
value
=
''
total
.
value
++
handleBackTopChildren
(
index
)
// 只需要刷新当前的评论
search
()
}
// 展开回复 获取子评论列表
...
...
@@ -397,11 +422,11 @@ const handleExpandReply = async (item: CommentItemDto) => {
item
.
loadingChildren
=
false
}
item
.
showChild
e
renPage
=
true
item
.
showChildrenPage
=
true
}
// 收起回复
const
handleCollapseReply
=
(
item
:
CommentItemDto
,
index
:
number
)
=>
{
item
.
showChild
e
renPage
=
false
item
.
showChildrenPage
=
false
handleBackTopChildren
(
index
)
}
...
...
@@ -426,7 +451,7 @@ const getCommentChildrenList = async (item: CommentItemDto) => {
// 获取当前要渲染的子列表
const
getCurrentChildrenList
=
(
item
:
CommentItemDto
)
=>
{
if
(
item
.
showChild
e
renPage
)
{
if
(
item
.
showChildrenPage
)
{
return
item
.
childrenPageList
}
else
{
return
item
.
children
...
...
@@ -437,3 +462,15 @@ defineExpose({
scrollToCommentBox
:
()
=>
handleBackTop
(),
})
</
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
>
src/hooks/useScrollTop.tsx
View file @
82eec017
...
...
@@ -28,7 +28,6 @@ export const useScrollTop = (
const
handleBackTop
=
(
currentIndex
:
number
=
0
)
=>
{
const
initDoms
=
unref
(
el
)
if
(
!
initDoms
)
return
let
doms
=
[]
...
...
src/layoutCulture/components/onlineTime.vue
View file @
82eec017
...
...
@@ -38,13 +38,16 @@
<div
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
class=
"absolute bottom-2 left-3 right-3 h-1 bg-gray-200 rounded-full overflow-hidden"
>
<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>
...
...
@@ -67,12 +70,49 @@
<
script
setup
lang=
"ts"
>
import
{
UseDraggable
as
Draggable
}
from
'@vueuse/components'
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
CONTAINER_WIDTH
=
130
,
CONTAINER_HEIGHT
=
170
,
GAP
=
30
const
maxSeconds
=
60
*
30
// 半小时
const
x
=
width
.
value
-
CONTAINER_WIDTH
-
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
>
src/layoutCulture/index.vue
View file @
82eec017
...
...
@@ -84,7 +84,7 @@
</div>
<div
class=
"flex-1 w-full flex items-center justify-center"
>
<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 }"
>
<transition
name=
"fade"
mode=
"out-in"
>
...
...
src/views/homePage/homeTab/components/recommendList.vue
View file @
82eec017
...
...
@@ -95,7 +95,7 @@
<el-pagination
v-model:current-page=
"searchParams.current"
v-model:page-size=
"searchParams.size"
:page-sizes=
"[5,
20, 1
]"
:page-sizes=
"[5,
10, 20
]"
layout=
"prev, pager, next, jumper, total"
:total=
"total"
class=
"custom-pagination"
...
...
@@ -134,7 +134,7 @@ const { list, total, searchParams, loading, goToPage, changePageSize, refresh }
{
defaultParams
:
{
sortLogic
:
0
},
defaultCurrent
:
1
,
defaultSize
:
5
,
defaultSize
:
8
,
immediate
:
false
,
},
)
...
...
src/views/homePage/yaTab/components/practiceList.vue
View file @
82eec017
...
...
@@ -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,20 +41,29 @@
{{
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>
<el-divider
class=
"my-1!"
/>
<div
class=
"divide-y bg-#fff"
>
<div
@
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
@
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-1"
>
...
...
@@ -56,8 +73,12 @@
<!-- 带图片的内容 -->
<div
class=
"flex gap-3 mb-3"
>
<img
v-if=
"item.faceUrl"
:src=
"item.faceUrl"
:alt=
"item.title"
class=
"w-20 h-20 object-cover rounded-lg flex-shrink-0"
/>
<img
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=
"text-gray-600 text-sm leading-relaxed line-clamp-3"
>
{{
item
.
content
}}
...
...
@@ -109,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>
...
...
@@ -154,7 +184,7 @@ const { list, total, searchParams, goToPage, changePageSize, refresh } = usePage
{
defaultParams
:
{
sortLogic
:
filterOptions
.
value
[
0
]?.
id
,
tagIdList
:
[]
},
defaultCurrent
:
1
,
defaultSize
:
5
,
defaultSize
:
8
,
immediate
:
false
,
},
)
...
...
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