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
1f06fdd6
Commit
1f06fdd6
authored
Dec 11, 2025
by
lijiabin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
【需求 17679】 feat: 加入问吧详情页面 优化评论组件等
parent
5f8e0353
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
279 additions
and
9 deletions
+279
-9
types.ts
src/api/article/types.ts
+30
-0
index.vue
src/components/common/Comment/index.vue
+4
-0
route.ts
src/router/route.ts
+5
-0
index.vue
src/views/homePage/askTab/index.vue
+17
-9
index.vue
src/views/questionDetail/index.vue
+223
-0
No files found.
src/api/article/types.ts
View file @
1f06fdd6
...
@@ -149,6 +149,36 @@ export interface ArticleItemDto {
...
@@ -149,6 +149,36 @@ export interface ArticleItemDto {
rewardNum
:
number
rewardNum
:
number
isExpand
:
boolean
isExpand
:
boolean
hasAddQuestion
:
boolean
hasAddQuestion
:
boolean
cultureCommentListVo
:
{
articleId
:
number
avatar
:
string
children
:
string
childrenNum
:
number
content
:
string
createTime
:
number
createUserId
:
number
description
:
string
faceUrl
:
string
hasPraise
:
BooleanFlag
hiddenAvatar
:
string
hiddenName
:
string
id
:
number
isFeatured
:
BooleanFlag
isRecommend
:
BooleanFlag
isTop
:
BooleanFlag
pid
:
number
postPriseCount
:
number
praiseCount
:
number
region
:
string
regionHide
:
BooleanFlag
replyId
:
number
replyName
:
string
replyUser
:
string
title
:
string
type
:
ArticleTypeEnum
userId
:
string
viewCount
:
number
}
}
}
/**
/**
...
...
src/components/common/Comment/index.vue
View file @
1f06fdd6
...
@@ -308,10 +308,12 @@ const {
...
@@ -308,10 +308,12 @@ const {
id
,
id
,
defaultSize
=
10
,
defaultSize
=
10
,
isReal
,
isReal
,
immediate
=
true
,
}
=
defineProps
<
{
}
=
defineProps
<
{
id
:
number
|
string
id
:
number
|
string
defaultSize
?:
number
defaultSize
?:
number
isReal
:
BooleanFlag
isReal
:
BooleanFlag
immediate
?:
boolean
}
>
()
}
>
()
const
emit
=
defineEmits
<
{
const
emit
=
defineEmits
<
{
...
@@ -366,6 +368,7 @@ const { list, searchParams, goToPage, loading, changePageSize, refresh, search }
...
@@ -366,6 +368,7 @@ const { list, searchParams, goToPage, loading, changePageSize, refresh, search }
return
obj
return
obj
})
})
},
},
immediate
,
},
},
)
)
const
handleCurrentChange
=
async
(
e
:
number
)
=>
{
const
handleCurrentChange
=
async
(
e
:
number
)
=>
{
...
@@ -496,6 +499,7 @@ const handleUserInfo = (item: CommentItemDto) => {
...
@@ -496,6 +499,7 @@ const handleUserInfo = (item: CommentItemDto) => {
defineExpose
({
defineExpose
({
scrollToCommentBox
:
()
=>
handleBackTop
(),
scrollToCommentBox
:
()
=>
handleBackTop
(),
search
:
()
=>
search
(),
})
})
</
script
>
</
script
>
<
style
scoped
lang=
"scss"
>
<
style
scoped
lang=
"scss"
>
...
...
src/router/route.ts
View file @
1f06fdd6
...
@@ -161,6 +161,11 @@ export const constantsRoute = [
...
@@ -161,6 +161,11 @@ export const constantsRoute = [
name
:
'CultureVideoSearchList'
,
name
:
'CultureVideoSearchList'
,
component
:
()
=>
import
(
'@/views/videoSearchList/index.vue'
),
component
:
()
=>
import
(
'@/views/videoSearchList/index.vue'
),
},
},
{
path
:
'questionDetail/:id'
,
name
:
'CultureQuestionDetail'
,
component
:
()
=>
import
(
'@/views/questionDetail/index.vue'
),
},
// 发布文章
// 发布文章
// {
// {
// {
// {
...
...
src/views/homePage/askTab/index.vue
View file @
1f06fdd6
...
@@ -22,14 +22,15 @@
...
@@ -22,14 +22,15 @@
:key=
"item.id"
:key=
"item.id"
class=
"question-card !rounded-lg mb-4 transition-all duration-300"
class=
"question-card !rounded-lg mb-4 transition-all duration-300"
shadow=
"hover"
shadow=
"hover"
@
click=
"router.push(`/questionDetail/$
{item.id}`)"
>
>
<!-- 问题标题 -->
<!-- 问题标题 -->
<h
3
<h
2
class=
"text-
lg font-semibold text-gray-900 mb-3
leading-relaxed cursor-pointer hover:text-blue-600 transition-colors"
class=
"text-
xl line-clamp-1 font-semibold text-gray-900 mb-2
leading-relaxed cursor-pointer hover:text-blue-600 transition-colors"
>
>
{{
item
.
title
}}
{{
item
.
title
}}
</h
3
>
</h
2
>
<div
class=
"flex gap-4 mb-
4
"
>
<div
class=
"flex gap-4 mb-
2
"
>
<el-image
<el-image
v-if=
"item.faceUrl"
v-if=
"item.faceUrl"
:src=
"item.faceUrl"
:src=
"item.faceUrl"
...
@@ -43,7 +44,9 @@
...
@@ -43,7 +44,9 @@
class=
"text-gray-600 text-base leading-relaxed transition-all duration-300"
class=
"text-gray-600 text-base leading-relaxed transition-all duration-300"
:class=
"
{ 'line-clamp-3': !item.isExpand }"
:class=
"
{ 'line-clamp-3': !item.isExpand }"
>
>
{{
item
.
content
}}
{{
item
.
cultureCommentListVo
?.
hiddenAvatar
}}
:
{{
item
.
cultureCommentListVo
?.
content
}}
</p>
</p>
<!-- 展开/收起按钮 靠右边布局 -->
<!-- 展开/收起按钮 靠右边布局 -->
<div
class=
"flex justify-end"
>
<div
class=
"flex justify-end"
>
...
@@ -68,7 +71,7 @@
...
@@ -68,7 +71,7 @@
<!-- 左侧:发布人信息 -->
<!-- 左侧:发布人信息 -->
<div
class=
"flex items-center gap-4"
>
<div
class=
"flex items-center gap-4"
>
<div
class=
"flex items-center gap-2"
>
<div
class=
"flex items-center gap-2"
>
<
!--
<span
class=
"text-orange-500 text-sm font-medium"
>
发布人
</span>
--
>
<
span
class=
"text-orange-500 text-sm font-medium"
>
发布人
</span
>
<div
class=
"flex items-center gap-2"
>
<div
class=
"flex items-center gap-2"
>
<el-avatar
:size=
"20"
:src=
"item.showAvatar"
>
</el-avatar>
<el-avatar
:size=
"20"
:src=
"item.showAvatar"
>
</el-avatar>
<span
class=
"text-sm text-gray-700 font-medium"
>
{{
item
.
showName
}}
</span>
<span
class=
"text-sm text-gray-700 font-medium"
>
{{
item
.
showName
}}
</span>
...
@@ -106,7 +109,7 @@
...
@@ -106,7 +109,7 @@
</el-button>
</el-button>
<!-- 回答按钮保持不变 -->
<!-- 回答按钮保持不变 -->
<el-button
size=
"small"
plain
@
click=
"handleComment(item)"
>
<el-button
size=
"small"
plain
@
click=
"handleComment(item
, index
)"
>
<el-icon><Edit
/></el-icon>
<el-icon><Edit
/></el-icon>
回答
回答
</el-button>
</el-button>
...
@@ -139,7 +142,7 @@
...
@@ -139,7 +142,7 @@
<el-button
<el-button
text
text
class=
"flex items-center gap-2 text-gray-500 transition-colors"
class=
"flex items-center gap-2 text-gray-500 transition-colors"
@
click=
"handleComment(item)"
@
click=
"handleComment(item
, index
)"
>
>
<el-icon><ChatDotRound
/></el-icon>
<el-icon><ChatDotRound
/></el-icon>
<span
class=
"text-sm"
>
{{
item
.
replyCount
||
0
}}
</span>
<span
class=
"text-sm"
>
{{
item
.
replyCount
||
0
}}
</span>
...
@@ -149,10 +152,12 @@
...
@@ -149,10 +152,12 @@
<Transition
name=
"fade"
>
<Transition
name=
"fade"
>
<Comment
<Comment
v-show=
"item.showComment"
v-show=
"item.showComment"
:ref=
"(e) => (commentRefList[index] = e as InstanceType
<typeof
Comment
>
)"
:id="item.id"
:id="item.id"
:total="item.replyCount"
:total="item.replyCount"
:defaultSize="5"
:defaultSize="5"
:isReal="0"
:isReal="0"
:immediate="false"
@commentSuccess="() => handleCommentSuccess(item)"
@commentSuccess="() => handleCommentSuccess(item)"
/>
/>
</Transition>
</Transition>
...
@@ -215,6 +220,7 @@ import { getArticleList, addOrCanceArticlelCollect, addOrCancelToAnswerList } fr
...
@@ -215,6 +220,7 @@ import { getArticleList, addOrCanceArticlelCollect, addOrCancelToAnswerList } fr
import
type
{
ArticleItemDto
}
from
'@/api/article/types'
import
type
{
ArticleItemDto
}
from
'@/api/article/types'
import
{
useQuestionStore
}
from
'@/stores/question'
import
{
useQuestionStore
}
from
'@/stores/question'
import
ActionMore
from
'@/components/common/ActionMore/index.vue'
import
ActionMore
from
'@/components/common/ActionMore/index.vue'
import
router
from
'@/router'
const
{
fetchUserQestionNum
}
=
useQuestionStore
()
const
{
fetchUserQestionNum
}
=
useQuestionStore
()
...
@@ -253,7 +259,8 @@ const handleCollect = async (item: ArticleItemDto) => {
...
@@ -253,7 +259,8 @@ const handleCollect = async (item: ArticleItemDto) => {
ElMessage
.
success
(
item
.
hasCollect
?
'收藏成功'
:
'取消收藏'
)
ElMessage
.
success
(
item
.
hasCollect
?
'收藏成功'
:
'取消收藏'
)
}
}
const
handleComment
=
(
item
:
ArticleItemDto
)
=>
{
const
handleComment
=
(
item
:
ArticleItemDto
,
index
:
number
)
=>
{
commentRefList
.
value
[
index
]?.
search
()
item
.
showComment
=
!
item
.
showComment
item
.
showComment
=
!
item
.
showComment
}
}
...
@@ -283,6 +290,7 @@ const handleTabChange = () => {
...
@@ -283,6 +290,7 @@ const handleTabChange = () => {
}
}
const
contentRefList
=
ref
<
HTMLElement
[]
>
([])
const
contentRefList
=
ref
<
HTMLElement
[]
>
([])
const
commentRefList
=
ref
<
InstanceType
<
typeof
Comment
>
[]
>
([])
// 检测当前是否超过三行 要用到具体的dom
// 检测当前是否超过三行 要用到具体的dom
const
isOverThreeLine
=
(
index
:
number
)
=>
{
const
isOverThreeLine
=
(
index
:
number
)
=>
{
...
...
src/views/questionDetail/index.vue
0 → 100644
View file @
1f06fdd6
<
script
setup
lang=
"ts"
>
import
{
ref
}
from
'vue'
import
{
CaretTop
,
CaretBottom
,
ChatDotRound
,
Share
,
Star
,
Plus
}
from
'@element-plus/icons-vue'
// --- 模拟数据 ---
const
tags
=
ref
([
{
id
:
1
,
name
:
'React'
},
{
id
:
2
,
name
:
'Vue.js'
},
])
const
question
=
ref
({
title
:
'vue转react是什么感受?'
,
description
:
'最近在面试,有一家公司各方面都很满意,但是因为他们是做阿里巴巴网店模板,只能用react写,所以要考虑学习react,来知乎问问各位大佬意见...'
,
viewCount
:
'12,304'
,
followCount
:
52
,
})
const
answers
=
ref
([
{
id
:
1
,
user
:
{
name
:
'我们'
,
avatar
:
'https://picsum.photos/id/64/100/100'
,
bio
:
'各位都脑测了就回复了,你们的一切脑测都是对的'
,
},
votes
:
2
,
content
:
'什么时候这群人才能明白框架没那么重要,重要的是逻辑能力和代码水平'
,
publishDate
:
'2025-10-13 11:42'
,
commentCount
:
0
,
},
{
id
:
2
,
user
:
{
name
:
'老富甲'
,
avatar
:
'https://picsum.photos/id/1025/100/100'
,
bio
:
'程序员'
,
},
votes
:
12
,
content
:
`初入前端的时候,写的是 vue 2,非常简单的就入门了,然后就是自己研究html和css,对调样式很感兴趣,乐在其中。<br><br>换公司学 react,由于连 ts 都不会,同时学 react 官网和 ts 官网,两个官网都撸了4-5遍,差不多3天吧,就差不多能写基础的页面了,后续就是熟练度问题了,然后就是要学习各种组件库,其实还好,不会很难的,并且会了之后感觉很爽,比写vue爽了非常非常多。<br><br>写 react 我感觉就是比写 vue 更有激情,可能因为 vscode 对 ts、react 的插件体验更好点...`
,
publishDate
:
'2025-10-12 18:20'
,
commentCount
:
2
,
},
])
const
isFollowing
=
ref
(
false
)
</
script
>
<
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"
>
<!-- 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"
>
{{
tag
.
name
}}
</el-tag>
</div>
<!-- 标题 -->
<h1
class=
"text-2xl font-bold text-gray-900 mb-3 leading-snug"
>
{{
question
.
title
}}
</h1>
<!-- 描述 -->
<p
class=
"text-gray-600 leading-relaxed mb-6 text-sm md:text-base"
>
{{
question
.
description
}}
<span
class=
"text-blue-600 cursor-pointer hover:underline text-sm font-medium ml-1"
>
显示全部
</span
>
</p>
<!-- 操作栏 -->
<div
class=
"flex flex-wrap items-center justify-between gap-4 pt-2"
>
<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"
>
<el-icon
class=
"mr-1"
><Plus
/></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>
</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"
>
<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
class=
"text-base"
><Share
/></el-icon>
<span>
分享
</span>
</div>
</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>
</div>
</div>
<!-- 3. 回答列表 -->
<div
class=
"space-y-3"
>
<div
v-for=
"answer in answers"
:key=
"answer.id"
class=
"bg-white rounded-xl p-8 shadow-sm border border-gray-100 hover:shadow-md transition-shadow duration-200"
>
<!-- 用户 -->
<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>
</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>
<!-- 正文 -->
<div
class=
"text-gray-800 leading-7 text-sm md:text-base mb-6"
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"
>
<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"
>
<el-icon
class=
"mr-1"
><CaretTop
/></el-icon>
赞同
{{
answer
.
votes
}}
</button>
<button
class=
"flex items-center px-2 py-1 text-blue-400 hover:text-blue-600 transition-colors ml-0.5"
>
<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>
</div>
<div
class=
"flex items-center gap-1 cursor-pointer hover:text-gray-600 transition-colors"
>
<el-icon
class=
"text-base"
><Share
/></el-icon>
<span
class=
"text-xs"
>
分享
</span>
</div>
<div
class=
"flex items-center gap-1 cursor-pointer hover:text-gray-600 transition-colors"
>
<el-icon
class=
"text-base"
><Star
/></el-icon>
<span
class=
"text-xs"
>
收藏
</span>
</div>
<span
class=
"ml-auto text-xs text-gray-300 hidden sm:block"
>
{{
answer
.
publishDate
}}
</span>
</div>
</div>
</div>
</div>
</div>
</
template
>
<
style
scoped
>
/*
样式微调:
1. 卡片边框改为 border-gray-100,这是一种极淡的边框,配合阴影,质感更细腻。
2. 字体大小微调:正文使用 text-sm md:text-base,让信息密度稍微高一点,更像知乎PC端的阅读体验。
*/
</
style
>
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