Commit cfe3bd46 by lijiabin

【需求 17679】 perf: 优化问吧、评论等页面

parent 9662ea89
......@@ -219,6 +219,9 @@ export interface ColumnItemDto {
title: string
type: ArticleTypeEnum.COLUMN
viewCount: number
videoDuration: string
showName: string
showAvatar: string
}[]
}
......@@ -331,6 +334,8 @@ export interface CommentItemDto {
childrenPageCurrent: number
childrenPageList: CommentItemDto[]
loadingChildren: boolean
showComment: boolean
isExpand: boolean
}
/**
......
......@@ -10,7 +10,13 @@
:src="articleDetail?.createUserAvatar"
alt=""
class="w-12 h-12 rounded-full object-cover cursor-pointer"
@click="router.push(`/otherUserPage/${articleDetail?.createUserId}/0`)"
@click="
jumpToUserHomePage({
userId: articleDetail?.createUserId,
isReal:
articleDetail.type === 'practice' || articleDetail.type === 'interview' ? 1 : 0,
})
"
/>
<!-- <div
class="absolute -bottom-1 -right-1 w-6 h-6 bg-gradient-to-r from-yellow-400 to-orange-400 rounded-full flex items-center justify-center text-xs font-bold text-white"
......@@ -105,8 +111,8 @@ import dayjs from 'dayjs'
import type { ArticleItemDto } from '@/api'
import { articleTypeListOptions, ArticleTypeEnum } from '@/constants'
import ActionMore from '@/components/common/ActionMore/index.vue'
import { jumpToUserHomePage } from '@/utils'
const router = useRouter()
const { articleDetail } = defineProps<{
articleDetail: ArticleItemDto
}>()
......
......@@ -64,7 +64,7 @@
:src="userAvatar"
alt=""
class="w-10 h-10 rounded-full object-cover cursor-pointer"
@click="router.push(`/userPage`)"
@click="jumpToUserHomePage({ userId: userInfo.userId, isReal: 0 })"
/>
<div class="flex-1">
<div ref="commentInputRef">
......@@ -106,7 +106,7 @@
<div class="p-4 transition-colors">
<div class="flex gap-3">
<img
@click="handleUserInfo(item)"
@click="jumpToUserHomePage({ userId: item.userId, isReal: isReal })"
:src="item.avatar"
alt=""
class="w-10 h-10 rounded-full object-cover cursor-pointer"
......@@ -159,7 +159,7 @@
class="flex gap-2 p-3 rounded-lg"
>
<img
@click="handleUserInfo(child)"
@click="jumpToUserHomePage({ userId: child.userId, isReal: isReal })"
:src="child.avatar"
alt=""
class="w-8 h-8 rounded-full object-cover cursor-pointer"
......@@ -215,7 +215,7 @@
</div>
</template>
<!-- 只有大于5 才会显示这个 -->
<div class="ml-4" v-show="item.childrenNum > 5">
<div class="ml-4" v-show="item.childrenNum > 5 && !isQuestion">
<!-- 展示 展开回复 -->
<button
v-show="!item.showChildrenPage"
......@@ -249,41 +249,41 @@
</div>
</div>
<!-- 展示 回复评论的输入框 -->
<!-- <transition name="fade" mode="out-in"> -->
<div v-show="showCommentBox(item)" class="flex gap-3 mt-4">
<img
:src="userAvatar"
alt=""
class="w-10 h-10 rounded-full object-cover cursor-pointer"
@click="router.push(`/userPage`)"
/>
<div class="flex-1">
<el-input
v-model="comment"
type="textarea"
:placeholder="replyPlaceholder"
:rows="3"
></el-input>
<div class="flex justify-between items-center mt-3">
<div class="flex items-center gap-2 text-sm text-gray-500">
<button class="hover:text-blue-500 transition-colors">
<i class="i-carbon-face-satisfied"></i>
</button>
<button class="hover:text-blue-500 transition-colors">
<i class="i-carbon-image"></i>
<transition name="fade" mode="in-out">
<div v-show="showCommentBox(item)" class="flex gap-3 mt-4">
<img
:src="userAvatar"
alt=""
class="w-10 h-10 rounded-full object-cover cursor-pointer"
@click="jumpToUserHomePage({ userId: userInfo.userId, isReal: isReal })"
/>
<div class="flex-1">
<el-input
v-model="comment"
type="textarea"
:placeholder="replyPlaceholder"
:rows="3"
></el-input>
<div class="flex justify-between items-center mt-3">
<div class="flex items-center gap-2 text-sm text-gray-500">
<button class="hover:text-blue-500 transition-colors">
<i class="i-carbon-face-satisfied"></i>
</button>
<button class="hover:text-blue-500 transition-colors">
<i class="i-carbon-image"></i>
</button>
</div>
<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(index)"
>
发表
</button>
</div>
<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(index)"
>
发表
</button>
</div>
</div>
</div>
<!-- </transition> -->
</transition>
</div>
</div>
</div>
......@@ -309,7 +309,7 @@
</div>
</div>
</div>
<CommentDialog ref="commentDialogRef" :articleId="id" :pid="currentDialogCommentPid" />
<CommentListDialog ref="commentListDialogRef" :articleId="id" :pid="currentDialogCommentPid" />
</div>
</template>
<script lang="ts" setup>
......@@ -326,7 +326,8 @@ import type { CommentItemDto } from '@/api'
import dayjs from 'dayjs'
import { useUserStore } from '@/stores'
import { storeToRefs } from 'pinia'
import CommentDialog from '../CommentDialog/index.vue'
import CommentListDialog from '../CommentListDialog/index.vue'
import { jumpToUserHomePage } from '@/utils'
const {
id,
defaultSize = 10,
......@@ -354,7 +355,7 @@ const userStore = useUserStore()
const { userInfo } = storeToRefs(userStore)
const userAvatar = computed(() => (isReal ? userInfo.value.avatar : userInfo.value.hiddenAvatar))
const commentRef = useTemplateRef<HTMLElement | null>('commentRef')
const commentDialogRef = useTemplateRef<HTMLElement | null>('commentDialogRef')
const commentListDialogRef = useTemplateRef<typeof CommentListDialog>('commentListDialogRef')
const commentInputRef = useTemplateRef<HTMLElement | null>('commentInputRef')
const commentItemRefList = ref<HTMLElement[]>([])
// 回滚到评论框
......@@ -525,14 +526,10 @@ const getCurrentChildrenList = (item: CommentItemDto) => {
}
}
const handleUserInfo = (item: CommentItemDto) => {
router.push(`/otherUserPage/${item.userId}/${isReal}`)
}
const currentDialogCommentPid = ref(0)
const handleOpenCommentDialog = (item: CommentItemDto) => {
currentDialogCommentPid.value = item.id
commentDialogRef.value?.open()
commentListDialogRef.value?.open()
}
defineExpose({
......@@ -541,14 +538,12 @@ defineExpose({
})
</script>
<style scoped lang="scss">
.fade-enter-from,
.fade-leave-to {
.fade-enter-from {
opacity: 0;
transform: translateY(10px);
transform: translateY(-10px);
}
.fade-enter-active,
.fade-leave-active {
transition: all 0.3s ease;
.fade-enter-active {
transition: all 0.5s ease-out;
}
</style>
......@@ -96,11 +96,7 @@ const widthRate = computed(() => {
// 在线时长格式化 将秒级 格式化为 00:00
const formatSeconds = computed(() => {
if (currentSeconds.value >= maxSeconds) {
return '30:00'
} else {
return dayjs.utc(currentSeconds.value * 1000).format('mm:ss')
}
return dayjs.utc(currentSeconds.value * 1000).format('mm:ss')
})
onMounted(async () => {
......
......@@ -167,7 +167,7 @@ export const constantsRoute = [
component: () => import('@/views/questionDetail/index.vue'),
},
{
path: 'publishLongArticle',
path: 'publishLongArticle/:type',
name: 'CulturePublishLongArticle',
component: () => import('@/views/publishLongArticle/index.vue'),
},
......
import type { ArticleType, BooleanFlag } from '@/constants'
import { useUserStore } from '@/stores'
import { storeToRefs } from 'pinia'
/**
* 页面改变标题
* @param title
......@@ -59,3 +62,26 @@ export function isCulturePath() {
const path = window.location.pathname
return path.includes('/culture')
}
// 点击头像跳转用户首页
export function jumpToUserHomePage({ userId, isReal }: { userId: number; isReal: BooleanFlag }) {
const userStore = useUserStore()
const { userInfo } = storeToRefs(userStore)
const isSelf = userInfo.value.userId === userId
if (isSelf) {
window.open(`/userPage/selfPublish`)
} else {
window.open(`/otherUserPage/${userId}/${isReal}`)
}
}
// 根据文章类型跳到对应的文章详情页面
export function jumpToArticleDetailPage({ type, id }: { type: ArticleType; id: number }) {
if (type === 'video') {
window.open(`/videoDetail/${id}`)
} else if (type === 'question') {
window.open(`/questionDetail/${id}`)
} else {
window.open(`/articleDetail/${id}`)
}
}
export * from './app'
......@@ -68,7 +68,7 @@ export function selectDepOrUser(wxOption = {}): Promise<ISelectDepOrUser> {
...wxOption,
}
return new Promise((resolve, reject) => {
wx.invoke('selectEnterpriseContact', option, function (res: ISelectDepOrUser) {
ww.invoke('selectEnterpriseContact', option, function (res: ISelectDepOrUser) {
if (res.err_msg == 'selectEnterpriseContact:ok') {
resolve(res)
}
......
......@@ -44,9 +44,15 @@
class="text-gray-600 text-base leading-relaxed transition-all duration-300"
:class="{ 'line-clamp-3': !item.isExpand }"
>
{{ item.cultureCommentListVo?.hiddenName }}{{
item.cultureCommentListVo?.content
}}
<!-- 如果有评论的话 就展示 最热的 没有的话 说明没有评论 就展示内容 -->
<template v-if="item.cultureCommentListVo?.hiddenName">
{{ item.cultureCommentListVo?.hiddenName }}{{
item.cultureCommentListVo?.content
}}
</template>
<template v-else>
{{ item.content }}
</template>
</p>
<!-- 展开/收起按钮 靠右边布局 -->
<div class="flex justify-end">
......@@ -112,7 +118,12 @@
<!-- 当前最热评论的评论有几条 -->
<el-button size="small" plain @click.stop="handleComment(item, index)">
<el-icon><Edit /></el-icon>
{{ item.cultureCommentListVo?.childNum || 0 }}条评论
<template v-if="item.cultureCommentListVo?.childNum">
{{ item.cultureCommentListVo?.childNum }}条评论
</template>
<template v-else>
<span>写评论</span>
</template>
</el-button>
<ActionMore class="ml-4" :articleDetail="item" />
......@@ -152,7 +163,7 @@
</div>
<Transition name="fade">
<Comment
v-show="item.showComment"
v-if="item.showComment"
:ref="(e) => (commentRefList[index] = e as InstanceType<typeof Comment>)"
:id="item.id"
:total="item.cultureCommentListVo?.childNum || 0"
......@@ -183,6 +194,13 @@
<el-pagination
v-model:current-page="searchParams.current"
v-model:page-size="searchParams.size"
@current-change="
async (e) => {
await goToPage(e)
handleBackTop()
}
"
@size-change="changePageSize"
:page-sizes="[15, 30, 45, 60]"
layout="prev, pager, next, jumper, total"
:total="total"
......@@ -207,6 +225,7 @@
</el-tour-step>
<template #indicators></template>
</el-tour>
<CommentDialog ref="commentDialogRef" @commentSuccess="search" />
</div>
</template>
......@@ -223,12 +242,14 @@ import { getArticleList, addOrCanceArticlelCollect, addOrCancelToAnswerList } fr
import type { ArticleItemDto } from '@/api/article/types'
import { useQuestionStore } from '@/stores/question'
import ActionMore from '@/components/common/ActionMore/index.vue'
import CommentDialog from '@/components/common/CommentDialog/index.vue'
const { fetchUserQestionNum } = useQuestionStore()
const route = useRoute()
const open = ref(false)
const publishBoxRef = useTemplateRef('publishBoxRef')
const commentDialogRef = useTemplateRef<typeof CommentDialog>('commentDialogRef')
const activeTab = ref('最新')
const tabs = [
......@@ -237,18 +258,19 @@ const tabs = [
{ label: '关注', value: '关注' },
]
const { list, total, searchParams, loading, refresh } = usePageSearch(getArticleList, {
immediate: false,
defaultParams: {
type: ArticleTypeEnum.QUESTION,
},
formatList: (list) =>
list.map((item) => ({
...item,
showComment: false,
isExpand: false,
})),
})
const { list, total, searchParams, loading, refresh, goToPage, changePageSize, search } =
usePageSearch(getArticleList, {
immediate: false,
defaultParams: {
type: ArticleTypeEnum.QUESTION,
},
formatList: (list) =>
list.map((item) => ({
...item,
showComment: false,
isExpand: false,
})),
})
const tabsRef = inject(TABS_REF_KEY)
......@@ -261,9 +283,19 @@ const handleCollect = async (item: ArticleItemDto) => {
ElMessage.success(item.hasCollect ? '收藏成功' : '取消收藏')
}
const handleComment = (item: ArticleItemDto, index: number) => {
commentRefList.value[index]?.search()
item.showComment = !item.showComment
// 一个是直接写这个问题的首评论 一个是直接给最热评论写评论
const handleComment = async (item: ArticleItemDto, index: number) => {
if (item.cultureCommentListVo?.hiddenName) {
item.showComment = !item.showComment
await nextTick()
if (item.showComment) {
commentRefList.value[index]?.search()
}
} else {
// 直接让他写评论
commentDialogRef.value?.open(item.id)
}
}
const handleCommentSuccess = (item: ArticleItemDto) => {
......
......@@ -6,7 +6,7 @@
v-for="item in list"
:key="item.id"
class="group bg-white rounded-lg p-4 sm:p-6 cursor-pointer transition-all duration-300 hover:shadow-lg hover:shadow-gray-100 hover:-translate-y-1 border border-gray-100 hover:border-gray-200 mb-3 sm:mb-4"
@click="handleClickItem(item)"
@click="jumpToArticleDetailPage({ type: item.type, id: item.id })"
>
<div class="flex gap-3 justify-between">
<!-- <div
......@@ -26,7 +26,7 @@
</h2>
<!-- 内容摘要 -->
<div class="my-2 space-y-1">
<div v-if="!item.content?.includes('</')" class="my-2 space-y-1">
<p
class="text-gray-600 text-sm sm:text-base leading-relaxed line-clamp-1 break-all"
>
......@@ -38,6 +38,19 @@
<div
class="flex flex-wrap items-center gap-2 sm:gap-4 text-gray-500 text-xs sm:text-sm"
>
<!-- 发布人名称和头像 -->
<div class="flex items-center gap-2">
<el-avatar :size="24" :src="item.showAvatar" />
<span class="text-sm text-gray-500">{{ item.showName }}</span>
</div>
<!-- 时间 -->
<span class="text-gray-500 font-medium ml-auto sm:ml-0">
<span class="hidden sm:inline">{{
dayjs(item.createTime * 1000).format('YYYY-MM-DD HH:mm')
}}</span>
</span>
<!-- 分隔符 -->
<div class="hidden sm:block w-1 h-1 bg-gray-300 rounded-full"></div>
<div class="flex items-center gap-1 hover:text-blue-500 transition-colors">
<el-icon class="text-sm"><View /></el-icon>
<span class="font-medium">{{ item.viewCount }}</span>
......@@ -50,20 +63,6 @@
<el-icon class="text-sm"><Star /></el-icon>
<span class="font-medium">{{ item.collectionCount }}</span>
</div>
<!-- 分隔符 -->
<div class="hidden sm:block w-1 h-1 bg-gray-300 rounded-full"></div>
<!-- 发布人名称和头像 -->
<div class="flex items-center gap-2">
<el-avatar :size="24" :src="item.showAvatar" />
<span class="text-sm text-gray-500">{{ item.showName }}</span>
</div>
<!-- 时间 -->
<span class="text-gray-500 font-medium ml-auto sm:ml-0">
<span class="hidden sm:inline">{{
dayjs(item.createTime * 1000).format('YYYY-MM-DD HH:mm')
}}</span>
</span>
</div>
</div>
......@@ -106,8 +105,9 @@
:total="total"
class="custom-pagination"
@current-change="
(e) => {
;(handleBackTop(), goToPage(e))
async (e) => {
await goToPage(e)
handleBackTop()
}
"
@size-change="changePageSize"
......@@ -128,10 +128,11 @@
<script setup lang="ts">
import { usePageSearch } from '@/hooks'
import { getArticleList, type ArticleItemDto } from '@/api'
import { TABS_REF_KEY, ArticleTypeEnum } from '@/constants'
import { getArticleList } from '@/api'
import { TABS_REF_KEY } from '@/constants'
import { useScrollTop } from '@/hooks'
import dayjs from 'dayjs'
import { jumpToArticleDetailPage } from '@/utils'
const { list, total, searchParams, loading, goToPage, changePageSize, refresh } = usePageSearch(
getArticleList,
......@@ -146,14 +147,6 @@ const tabsRef = inject(TABS_REF_KEY)
const { ScrollTopComp, handleBackTop } = useScrollTop(tabsRef!)
const handleClickItem = (item: ArticleItemDto) => {
if (item.type === ArticleTypeEnum.VIDEO) {
window.open(`/videoDetail/${item.id}`)
} else {
window.open(`/articleDetail/${item.id}`)
}
}
defineExpose({
refresh: (sortLogic?: number) => {
console.log('sortLogic', sortLogic)
......
......@@ -37,7 +37,7 @@
v-for="i in item.yaColumnVoList"
:key="i.articleId"
class="group cursor-pointer"
@click="openArticleDetail(i.articleId)"
@click="jumpToArticleDetailPage({ type: i.type, id: i.articleId })"
>
<div class="relative mb-3 overflow-hidden rounded-lg">
<img
......@@ -133,9 +133,10 @@
import { View, ChatDotRound, Star } from '@element-plus/icons-vue'
import { getColumnList } from '@/api'
import { usePageSearch, useScrollTop } from '@/hooks'
import { ArticleTypeEnum, TABS_REF_KEY } from '@/constants'
import { TABS_REF_KEY } from '@/constants'
import dayjs from 'dayjs'
import { useRouter } from 'vue-router'
import { jumpToArticleDetailPage } from '@/utils'
const router = useRouter()
const tabsRef = inject(TABS_REF_KEY)
const { handleBackTop, ScrollTopComp } = useScrollTop(tabsRef!)
......@@ -153,10 +154,6 @@ defineExpose({
refresh()
},
})
const openArticleDetail = (id: number) => {
window.open(`/articleDetail/${id}`)
}
</script>
<style scoped></style>
......@@ -35,7 +35,7 @@
v-for="i in item.yaColumnVoList"
:key="i.articleId"
class="group cursor-pointer"
@click="openArticleDetail(i.articleId)"
@click="jumpToArticleDetailPage({ type: i.type, id: i.articleId })"
>
<div class="relative mb-3 overflow-hidden rounded-lg">
<img
......@@ -107,8 +107,9 @@
:total="total"
class="custom-pagination"
@current-change="
(e) => {
;(handleBackTop(), goToPage(e))
async (e) => {
await goToPage(e)
handleBackTop()
}
"
@size-change="changePageSize"
......@@ -134,6 +135,7 @@ import { usePageSearch, useScrollTop } from '@/hooks'
import { TABS_REF_KEY, ArticleTypeEnum } from '@/constants'
import { useRouter } from 'vue-router'
import dayjs from 'dayjs'
import { jumpToArticleDetailPage } from '@/utils'
const router = useRouter()
const tabsRef = inject(TABS_REF_KEY)
......@@ -151,10 +153,6 @@ defineExpose({
refresh()
},
})
const openArticleDetail = (id: number) => {
window.open(`/articleDetail/${id}`)
}
</script>
<style scoped></style>
......@@ -57,7 +57,7 @@
</div>
<div class="divide-y bg-#fff">
<div
@click="openArticleDetail(item.id)"
@click="jumpToArticleDetailPage({ type: ArticleTypeEnum.PRACTICE, id: item.id })"
v-for="item in list"
:key="item.id"
class="p-4 hover:bg-gray-50 transition-colors cursor-pointer pl-8"
......@@ -141,8 +141,9 @@
:total="total"
class="custom-pagination"
@current-change="
(e) => {
;(handleBackTop(), goToPage(e))
async (e) => {
await goToPage(e)
handleBackTop()
}
"
@size-change="changePageSize"
......@@ -164,6 +165,7 @@ import { TABS_REF_KEY } from '@/constants'
import { useTagsStore } from '@/stores/tags'
import PublishPractice from '@/components/common/PublishBox/index.vue'
import { ArticleTypeEnum } from '@/constants'
import { jumpToArticleDetailPage } from '@/utils'
const tagsStore = useTagsStore()
const { tagList } = storeToRefs(tagsStore)
......@@ -215,10 +217,6 @@ defineExpose({
refresh()
},
})
const openArticleDetail = (id: number) => {
window.open(`/articleDetail/${id}`)
}
</script>
<style scoped></style>
......@@ -31,7 +31,7 @@
</div>
<div v-loading="loadingMore" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 mb-6">
<div
@click="handleOpenPage(item.articleId) "
@click="jumpToArticleDetailPage({ type: ArticleTypeEnum.VIDEO, id: item.articleId })"
v-for="item in listMore"
:key="item.articleId"
class="group relative rounded-lg overflow-hidden bg-white shadow-sm hover:shadow-lg transition-all duration-300 cursor-pointer"
......@@ -79,16 +79,6 @@
<span>{{ item.replyCount }}</span>
</div>
</div>
<!-- 播放按钮 -->
<!-- <div
class="absolute inset-0 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity duration-300"
>
<div
class="bg-white/90 backdrop-blur-sm rounded-full flex items-center justify-center shadow-xl transform scale-90 group-hover:scale-100 transition-transform duration-300"
>
<el-icon size="50" color="#333"><VideoPlay /></el-icon>
</div>
</div> -->
</div>
<div class="p-4">
......@@ -145,10 +135,77 @@
<div
v-for="i in item.yaColumnVoList"
:key="i.articleId"
class="group cursor-pointer"
@click="handleOpenPage(i.articleId)"
class="group cursor-pointer rounded-lg overflow-hidden"
@click="jumpToArticleDetailPage({ type: i.type, id: i.articleId })"
>
<div class="relative mb-3 overflow-hidden rounded-lg">
<div class="relative overflow-hidden">
<img
:src="i.faceUrl"
class="w-full h-44 object-cover group-hover:scale-105 transition-transform duration-500"
/>
<div class="absolute inset-0 bg-gradient-to-t from-black/40 to-transparent"></div>
<!-- 标签 -->
<!-- <div
class="absolute top-3 left-3 bg-gradient-to-r from-indigo-500 to-purple-500 text-white px-2.5 py-1 rounded-full text-xs font-semibold"
>
{{ item.tagNameList[0] }}
</div> -->
<div
v-if="i.isRecommend"
class="absolute top-0 left-0 w-15 h-7 z-1000 bg-#FFF9B9 flex items-center justify-center border-2px border-solid border-#f4f0eb rounded-tl-lg rounded-br-lg"
>
<img class="w-6" src="@/assets/img/culture/recommend.png" alt="" />
<div class="text-12px text-#000 line-height-12px">推荐</div>
</div>
<!-- 时长 -->
<div
class="absolute bottom-3 right-3 bg-black/80 backdrop-blur-sm text-white px-2 py-1 rounded-lg text-xs"
>
{{ i.videoDuration }}
</div>
<!-- 数据 -->
<div class="absolute bottom-3 left-3 flex gap-3 text-white text-xs">
<div
class="flex items-center gap-1 bg-black/50 backdrop-blur-sm px-2 py-1 rounded-lg"
>
<el-icon class="text-sm"><View /></el-icon>
<span>{{ i.viewCount }}</span>
</div>
<div
class="flex items-center gap-1 bg-black/50 backdrop-blur-sm px-2 py-1 rounded-lg"
>
<el-icon class="text-sm"><ChatDotRound /></el-icon>
<span>{{ i.replyCount }}</span>
</div>
<div
class="flex items-center gap-1 bg-black/50 backdrop-blur-sm px-2 py-1 rounded-lg"
>
<el-icon class="text-sm"><Star /></el-icon>
<span>{{ i.replyCount }}</span>
</div>
</div>
</div>
<div class="p-4">
<h3
class="font-semibold text-base mb-2 group-hover:text-blue-600 transition-colors line-clamp-1"
>
{{ i.title }}
</h3>
<div class="flex items-center justify-between text-gray-500 text-xs">
<div class="flex items-center gap-2 max-w-55%">
<img :src="i.showAvatar" alt="" class="w-6 h-6 rounded-full object-cover" />
<el-tooltip :content="i.showName" placement="top">
<span class="font-medium">{{ i.showName }}</span>
</el-tooltip>
</div>
<span>{{ dayjs(i.createTime * 1000).format('YYYY-MM-DD HH:mm') }}</span>
</div>
</div>
<!-- <div class="relative mb-3 overflow-hidden rounded-lg">
<img
:src="i.faceUrl"
class="w-full aspect-[5/3] object-cover group-hover:scale-105 transition-transform duration-300"
......@@ -189,7 +246,7 @@
</span>
</div>
<span>{{ dayjs(i.createTime * 1000).format('YYYY-MM-DD HH:mm:ss') }}</span>
</div>
</div> -->
</div>
</div>
<div v-else class="flex items-center justify-center h-48">
......@@ -218,8 +275,9 @@
:total="total"
class="custom-pagination"
@current-change="
(e) => {
;(handleBackTop(), goToPage(e))
async (e) => {
await goToPage(e)
handleBackTop()
}
"
@size-change="changePageSize"
......@@ -242,9 +300,10 @@
import { View, ChatDotRound, Star } from '@element-plus/icons-vue'
import { getVideoList, getVideoListViewMore } from '@/api'
import { usePageSearch, useScrollTop } from '@/hooks'
import { TABS_REF_KEY } from '@/constants'
import { TABS_REF_KEY, ArticleTypeEnum } from '@/constants'
import { useRouter } from 'vue-router'
import dayjs from 'dayjs'
import { jumpToArticleDetailPage } from '@/utils'
const router = useRouter()
const tabsRef = inject(TABS_REF_KEY)
......@@ -283,10 +342,6 @@ const changeSort = (sortLogic: number) => {
refreshMore()
}
const handleOpenPage = (articleId: number) => {
window.open(`/videoDetail/${articleId}`)
}
defineExpose({
refresh: () => {
// searchParams.value.current = 0
......
<template>
<div class="min-h-screen bg-[#fff] p-6 font-sans">
<div class="min-h-screen bg-[#fff] font-sans">
<div class="max-w-7xl mx-auto">
<!-- 顶部面包屑或标题(可选) -->
<el-form :model="form" label-position="top" class="grid grid-cols-12 gap-6 items-start">
<el-form
ref="formRef"
:model="form"
:rules="rules"
label-position="top"
class="grid grid-cols-12 gap-6 items-start"
>
<!-- 左侧:沉浸式创作区 (占 9 列) -->
<div class="col-span-12 lg:col-span-9 space-y-6">
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-8 min-h-[80vh]">
<!-- 标题输入:模拟大标题风格,去掉边框 -->
<el-form-item prop="title" class="mb-6 !border-b !border-gray-100 pb-2">
<el-form-item prop="title" class="!border-b !border-gray-100">
<el-input
v-model="form.title"
placeholder="请输入文章标题..."
class="title-input"
:maxlength="100"
show-word-limit
type="textarea"
:autosize="{ minRows: 1, maxRows: 2 }"
resize="none"
/>
</el-form-item>
<!-- 富文本编辑器 -->
<div class="editor-container">
<WangEditor v-model="form.content" style="height: 600px" />
<el-form-item prop="content" class="!border-b !border-gray-100">
<WangEditor v-model="form.content" style="height: 800px" />
</el-form-item>
</div>
</div>
</div>
<!-- 右侧:配置侧边栏 (占 3 列,吸顶) -->
<div class="col-span-12 lg:col-span-3 space-y-4 sticky top-4">
<div class="col-span-12 lg:col-span-3 space-y-4">
<!-- 卡片1:基础设置 -->
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-5">
<div class="font-bold text-gray-800 mb-4 flex items-center gap-2">
......@@ -39,10 +45,14 @@
<!-- 文章类型 -->
<el-form-item label="文章类型" prop="type">
<el-radio-group v-model="form.type" class="w-full grid grid-cols-3 gap-2">
<el-radio-button :value="ArticleTypeEnum.POST">帖子</el-radio-button>
<el-radio-button :value="ArticleTypeEnum.COLUMN">专栏</el-radio-button>
<el-radio-button :value="ArticleTypeEnum.INTERVIEW">专访</el-radio-button>
<el-radio-group
v-model="form.type"
class="w-full grid grid-cols-3 gap-2"
fill="#3b82f6"
>
<el-radio-button :value="ArticleTypeEnum.POST">{{
articleTypeListOptions.find((item) => item.value === type)?.label
}}</el-radio-button>
</el-radio-group>
</el-form-item>
......@@ -170,7 +180,15 @@
</div>
<div class="mb-6 flex items-center justify-end w-full">
<div class="flex gap-3">
<el-button type="primary" round class="!px-8 w-full!" @click="handlePublish">
<el-button class="rounded-lg" @click="handleClosed">取消</el-button>
<el-button class="rounded-lg" @click="handleSubmit(ReleaseStatusTypeEnum.DRAFT)">
存草稿
</el-button>
<el-button
type="primary"
@click="handleSubmit(ReleaseStatusTypeEnum.PUBLISH)"
class="px-6 py-2 bg-blue-500 hover:bg-blue-600 rounded-lg text-white text-sm font-medium shadow-sm hover:shadow-md transition-all duration-200"
>
发布
</el-button>
</div>
......@@ -182,8 +200,15 @@
</template>
<script setup lang="ts">
import type { FormInstance } from 'element-plus'
import WangEditor from '@/components/common/WangEditor/index.vue'
import { ArticleTypeEnum, SendTypeEnum, BooleanFlag, ReleaseStatusTypeEnum } from '@/constants'
import {
ArticleTypeEnum,
SendTypeEnum,
BooleanFlag,
ReleaseStatusTypeEnum,
articleTypeListOptions,
} from '@/constants'
import UploadFile from '@/components/common/UploadFile/index.vue'
import { useResetData } from '@/hooks'
import { useColumnStore } from '@/stores/column'
......@@ -192,9 +217,13 @@ import { addOrUpdateArticle } from '@/api'
// ... (逻辑部分保持不变,直接复用您的即可)
const columnStore = useColumnStore()
const { columnList } = storeToRefs(columnStore)
const router = useRouter()
const route = useRoute()
const type = route.params.type as ArticleTypeEnum
const formRef = useTemplateRef<FormInstance>('formRef')
const [form, resetForm] = useResetData({
articleType: ArticleTypeEnum.POST,
type: type,
title: '',
content: '',
faceUrl: '',
......@@ -208,13 +237,28 @@ const [form, resetForm] = useResetData({
releaseStatus: ReleaseStatusTypeEnum.PUBLISH,
})
const rules = {
title: [{ required: true, message: '请输入文章标题', trigger: 'blur' }],
content: [{ required: true, message: '请输入文章内容', trigger: 'blur' }],
type: [{ required: true, message: '请选择文章类型', trigger: 'blur' }],
faceUrl: [{ required: true, message: '请上传封面图', trigger: 'blur' }],
sendType: [{ required: true, message: '请选择发布类型', trigger: 'blur' }],
sendTime: [{ required: true, message: '请选择发布时间', trigger: 'blur' }],
releaseStatus: [{ required: true, message: '请选择发布状态', trigger: 'blur' }],
}
const filterTagsFn = (allTags: any[]) => {
return allTags.filter((tag) => tag.id !== Number(form.value.mainTagId))
}
const handlePublish = async () => {
const res = await addOrUpdateArticle(form.value)
console.log(res)
const handleSubmit = async () => {
try {
await formRef.value.validate()
const res = await addOrUpdateArticle(form.value)
console.log(res)
} catch (error) {
console.log(error)
}
}
</script>
......
<template>
<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">
<div class="min-h-screen pb-10 font-sans text-slate-800 flex justify-center px-20">
<div class="w-full space-y-4">
<!-- 1. 问题卡片 -->
<div
class="bg-white rounded-lg p-6 shadow-[0_1px_3px_rgba(0,0,0,0.02)] border border-slate-100"
......@@ -22,17 +22,17 @@
</h1>
<!-- 描述:次要信息,深灰 -->
<div class="text-slate-700 leading-relaxed text-[15px] mb-6">
<span :class="{ 'line-clamp-3': !isExpandDesc }">
<div class="text-gray-600 text-base leading-relaxed transition-all duration-300">
<div :class="{ 'line-clamp-3': !isExpand }" ref="questionContentRef">
{{ questionDetail.content }}
</span>
</div>
<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"
v-if="isOverThreeLine"
class="text-blue-500 text-sm font-medium hover:text-blue-600 mt-1 flex items-center gap-0.5 cursor-pointer"
@click="isExpand = !isExpand"
>
{{ isExpandDesc ? '收起' : '显示全部' }}
<el-icon :class="{ 'rotate-180': isExpandDesc }" class="transition-transform"
{{ isExpand ? '收起' : '显示全部' }}
<el-icon :class="{ 'rotate-180': isExpand }" class="transition-transform"
><CaretBottom
/></el-icon>
</button>
......@@ -42,7 +42,8 @@
<div class="flex items-center justify-between mt-4">
<div class="flex gap-3">
<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"
class="px-5 py-1.5 border !bg-blue-500 !text-white rounded-[4px] text-sm font-medium transition-colors flex items-center gap-1 cursor-pointer"
@click="openCommentDialog"
>
<el-icon><EditPen /></el-icon>
写回答
......@@ -81,7 +82,7 @@
<!-- 2. 列表控制栏 -->
<div
class="bg-white rounded-t-lg border-b border-slate-100 p-6 flex justify-between items-center shadow-sm"
class="bg-white rounded-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">
......@@ -89,6 +90,7 @@
size="small"
v-model="searchParams.sortType"
@change="(val) => changeSortType(val as number)"
fill="#3b82f6"
>
<el-radio-button label="最新" :value="2" />
<el-radio-button label="最多评论" :value="1" />
......@@ -135,20 +137,20 @@
>优秀回答</span
> -->
</div>
<div class="text-xs text-slate-400 mt-0.5 max-w-md truncate">
<!-- <div class="text-xs text-slate-400 mt-0.5 max-w-md truncate">
{{ answer.description || '暂无简介' }}
</div>
</div> -->
</div>
</div>
<!-- 赞同票数 (微小的灰色文字,增加信息密度) -->
<div class="text-xs text-slate-400 mb-2">
{{ answer.praiseCount || 0 }} 人赞同了该回答
{{ answer.postPriseCount || 0 }} 人赞同了该回答
</div>
<!-- 正文 -->
<!-- 正文 换行 -->
<div
class="text-slate-800 leading-7 text-[15px] mb-4 rich-text-content"
class="text-slate-800 leading-7 text-[15px] mb-4 rich-text-content break-all"
v-html="answer.content"
></div>
......@@ -167,7 +169,8 @@
>
<el-icon><CaretTop /></el-icon>
<span
>{{ answer.hasPraise ? '已赞同' : '赞同' }} {{ answer.praiseCount || '' }}</span
>{{ answer.hasPraise ? '已赞同' : '赞同' }}
{{ answer.postPriseCount || '' }}</span
>
</button>
<!-- <button
......@@ -182,7 +185,7 @@
@click="handleComment(answer, index)"
>
<el-icon class="text-base"><ChatRound /></el-icon>
<span :class="{ 'text-slate-800 font-medium': answer.showComment }">
<span>
{{ answer.childrenNum ? `${answer.childrenNum} 条评论` : '添加评论' }}
</span>
</button>
......@@ -204,7 +207,6 @@
:immediate="false"
:isQuestion="true"
:commentId="answer.id"
@commentSuccess="() => handleCommentSuccess(answer)"
/>
</div>
</Transition>
......@@ -212,18 +214,18 @@
</div>
<!-- 底部加载更多 -->
<div class="py-3 flex justify-center bg-#fff">
<div class="py-3 px-6 flex justify-end bg-#fff rounded-lg">
<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>
<CommentDialog ref="commentDialogRef" @commentSuccess="refresh" />
</div>
</template>
<script setup lang="ts">
......@@ -234,9 +236,10 @@ import {
addOrCanceArticlelCollect,
addOrCancelCommentLike,
} from '@/api'
import type { ArticleItemDto } from '@/api/types'
import type { ArticleItemDto } from '@/api'
import { usePageSearch } from '@/hooks'
import Comment from '@/components/common/Comment/index.vue'
import CommentDialog from '@/components/common/CommentDialog/index.vue'
import dayjs from 'dayjs'
const route = useRoute()
......@@ -244,11 +247,28 @@ const questionId = Number(route.params.id)
const commentRefList = ref<InstanceType<typeof Comment>[]>([])
const questionDetail = ref<ArticleItemDto>({} as ArticleItemDto)
const commentDialogRef = useTemplateRef<typeof CommentDialog>('commentDialogRef')
const questionContentRef = useTemplateRef<HTMLElement>('questionContentRef')
const isExpand = ref(false)
// 检测当前是否超过三行 要用到具体的dom
const isOverThreeLine = ref(false)
const checkIsOverThreeLine = () => {
if (!questionContentRef.value || !questionDetail.value.content) return false
const lineHeight = parseFloat(getComputedStyle(questionContentRef.value).lineHeight)
const height = questionContentRef.value!.scrollHeight
const maxHeight = lineHeight * 3
console.log(maxHeight, height)
return height > maxHeight
}
const getQuestionDetail = async () => {
const { data } = await getArticleDetail(questionId)
questionDetail.value = data
console.log(questionDetail.value)
await nextTick()
isOverThreeLine.value = checkIsOverThreeLine()
}
const { list, total, searchParams, goToPage, refresh } = usePageSearch(getCommentList, {
......@@ -276,7 +296,7 @@ const handleLikeArticle = async () => {
questionDetail.value.praiseCount = questionDetail.value.hasPraised
? questionDetail.value.praiseCount + 1
: questionDetail.value.praiseCount - 1
ElMessage.success(`${questionDetail.value.hasPraised ? '点赞成功' : '取消点赞成功'}`)
ElMessage.success(`${questionDetail.value.hasPraised ? '点赞该问题' : '取消点赞该问题'}`)
}
const handleCollectArticle = async () => {
......@@ -290,9 +310,9 @@ const handleCollectArticle = async () => {
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
answer.postPriseCount = answer.hasPraise ? answer.postPriseCount + 1 : answer.postPriseCount - 1
ElMessage.success(`${answer.hasPraise ? '点赞该回答' : '取消点赞该回答'}`)
}
const handleComment = (answer: any, index: number) => {
......@@ -300,6 +320,10 @@ const handleComment = (answer: any, index: number) => {
answer.showComment = !answer.showComment
}
const openCommentDialog = () => {
commentDialogRef.value?.open(questionDetail.value.id)
}
onMounted(() => {
getQuestionDetail()
})
......
......@@ -48,7 +48,11 @@
>
{{ dayjs(item.createTime * 1000).format('YYYY-MM-DD HH:mm:ss') }}
<span class="flex items-center px-2"> 举报帖子 </span>
<el-link type="primary" :underline="false" @click="handleToDetail(item)">
<el-link
type="primary"
:underline="false"
@click="jumpToArticleDetailPage({ type: item.type, id: item.articleId })"
>
{{ item.title }}
</el-link>
</span>
......@@ -118,9 +122,10 @@ import { getComplaintList, auditComplaint } from '@/api'
import { usePageSearch } from '@/hooks'
import { auditTypeListOptions } from '@/constants/options'
import dayjs from 'dayjs'
import { AuditStatusEnum, ArticleTypeEnum } from '@/constants'
import type { AuditComplaintDto, ComplaintListItemDto } from '@/api'
import { AuditStatusEnum } from '@/constants'
import type { AuditComplaintDto } from '@/api'
import type { TabPaneName } from 'element-plus'
import { jumpToArticleDetailPage } from '@/utils'
const toggleTab = (key: TabPaneName) => {
searchParams.value.status = key as AuditStatusEnum
......@@ -154,12 +159,4 @@ const handleAudit = async (data: AuditComplaintDto) => {
refresh()
}
const handleToDetail = (item: ComplaintListItemDto) => {
if (item.type === ArticleTypeEnum.VIDEO) {
window.open(`/videoDetail/${item.articleId}`)
} else {
window.open(`/articleDetail/${item.articleId}`)
}
}
</script>
......@@ -36,7 +36,12 @@
</div>
<div class="flex items-center text-gray-400 text-sm ml-4">
<el-button type="primary" link @click="openArticleDetail(item.id)"> 去回复 </el-button>
<el-button
type="primary"
link
@click="jumpToArticleDetailPage({ type: 'question', id: item.id })"
>去回复</el-button
>
</div>
</div>
</div>
......@@ -67,6 +72,7 @@ import { Document, Refresh } from '@element-plus/icons-vue'
import { answerQuestionPage } from '@/api'
import { usePageSearch } from '@/hooks'
import dayjs from 'dayjs'
import { jumpToArticleDetailPage } from '@/utils'
const { list, loading, searchParams, total, refresh, goToPage, changePageSize } = usePageSearch(
answerQuestionPage,
......@@ -77,8 +83,4 @@ const { list, loading, searchParams, total, refresh, goToPage, changePageSize }
onActivated(() => {
refresh()
})
const openArticleDetail = (id: number) => {
window.open(`/articleDetail/${id}`)
}
</script>
......@@ -47,7 +47,12 @@
</div>
<div class="flex items-center text-gray-400 text-sm ml-4">
<el-button type="primary" link @click="handleView(item)">查看</el-button>
<el-button
type="primary"
link
@click="jumpToArticleDetailPage({ type: item.type, id: item.id })"
>查看</el-button
>
</div>
</div>
</div>
......@@ -85,8 +90,8 @@ import {
import dayjs from 'dayjs'
import { ArticleTypeEnum } from '@/constants/enums'
import type { TabPaneName } from 'element-plus'
import type { SelfCollectDetailDto } from '@/api'
import { IS_REAL_KEY } from '@/constants/symbolKey'
import { jumpToArticleDetailPage } from '@/utils'
const isReal = inject(IS_REAL_KEY)
......@@ -111,14 +116,6 @@ const { list, loading, searchParams, total, refresh, goToPage, changePageSize }
},
)
const handleView = (item: SelfCollectDetailDto) => {
if (item.type === ArticleTypeEnum.VIDEO) {
window.open(`/videoDetail/${item.id}`)
} else {
window.open(`/articleDetail/${item.id}`)
}
}
onActivated(() => {
searchParams.value.type = filterArticleType.value[0]!.value
refresh()
......
......@@ -61,7 +61,12 @@
<!-- Meta Info -->
<div class="flex items-center text-gray-400 text-sm ml-4">
<el-button type="primary" link @click="handleView(item)">查看</el-button>
<el-button
type="primary"
link
@click="jumpToArticleDetailPage({ type: item.type, id: item.articleId })"
>查看</el-button
>
<el-button type="danger" link @click="handleDelete(item.id)">删除</el-button>
</div>
</div>
......@@ -99,9 +104,9 @@ import {
} from '@/constants/options'
import dayjs from 'dayjs'
import { CommentTypeEnum, ArticleTypeEnum } from '@/constants/enums'
import type { SelfCommentItemDto } from '@/api'
import type { TabPaneName } from 'element-plus'
import { IS_REAL_KEY } from '@/constants/symbolKey'
import { jumpToArticleDetailPage } from '@/utils'
const route = useRoute()
const isReal = inject(IS_REAL_KEY)
......@@ -140,14 +145,6 @@ const handleDelete = async (id: number) => {
refresh()
}
const handleView = (item: SelfCommentItemDto) => {
if (item.type === ArticleTypeEnum.VIDEO) {
window.open(`/videoDetail/${item.articleId}`)
} else {
window.open(`/articleDetail/${item.articleId}`)
}
}
onActivated(() => {
if (route.query.type) {
searchParams.value.type = route.query.type as ArticleTypeEnum
......
......@@ -46,7 +46,12 @@
</div>
<div class="flex items-center text-gray-400 text-sm ml-4">
<el-button type="primary" link @click="handleView(item)">查看</el-button>
<el-button
type="primary"
link
@click="jumpToArticleDetailPage({ type: item.type, id: item.id })"
>查看</el-button
>
</div>
</div>
</div>
......@@ -83,8 +88,8 @@ import {
} from '@/constants/options'
import dayjs from 'dayjs'
import { ArticleTypeEnum } from '@/constants/enums'
import type { SelfPraiseDetailDto } from '@/api'
import { IS_REAL_KEY } from '@/constants/symbolKey'
import { jumpToArticleDetailPage } from '@/utils'
const isReal = inject(IS_REAL_KEY)
......@@ -114,14 +119,6 @@ onActivated(() => {
refresh()
})
const handleView = (item: SelfPraiseDetailDto) => {
if (item.type === ArticleTypeEnum.VIDEO) {
window.open(`/videoDetail/${item.id}`)
} else {
window.open(`/articleDetail/${item.id}`)
}
}
defineExpose({
refresh: () => {
searchParams.value.type = filterArticleType.value[0]!.value
......
......@@ -47,7 +47,12 @@
</div>
<div class="flex items-center text-gray-400 text-sm ml-4">
<el-button type="primary" link @click="handleView(item)">查看</el-button>
<el-button
type="primary"
link
@click="jumpToArticleDetailPage({ type: item.type, id: item.id })"
>查看</el-button
>
<el-button type="danger" link @click="handleDelete(item.id)">删除</el-button>
</div>
</div>
......@@ -84,9 +89,9 @@ import {
} from '@/constants/options'
import dayjs from 'dayjs'
import { ArticleTypeEnum } from '@/constants/enums'
import type { SelfPublishDetailDto } from '@/api'
import type { TabPaneName } from 'element-plus'
import { IS_REAL_KEY } from '@/constants/symbolKey'
import { jumpToArticleDetailPage } from '@/utils'
const isReal = inject(IS_REAL_KEY)
const filterArticleType = computed(() => {
......@@ -115,13 +120,6 @@ onActivated(() => {
refresh()
})
const handleView = (item: SelfPublishDetailDto) => {
if (item.type === ArticleTypeEnum.VIDEO) {
window.open(`/videoDetail/${item.id}`)
} else {
window.open(`/articleDetail/${item.id}`)
}
}
const handleDelete = async (articleId: number) => {
await ElMessageBox.confirm('确定删除该吗?', '提示', {
confirmButtonText: '确定',
......
......@@ -28,8 +28,15 @@
@click="handleBackUser"
>返回个人账号</el-button
>
<!-- v-if="userInfo.isAdmin" 暂时不加权限 -->
<el-button type="primary" plain size="small" @click="handleAdmin">后台管理</el-button>
<!-- 暂时不加权限 -->
<el-button
v-if="userInfo.isAdmin || userInfo.isOfficialAccount"
type="primary"
plain
size="small"
@click="handleAdmin"
>后台管理</el-button
>
</div>
</div>
......
......@@ -39,7 +39,7 @@
<!-- 左侧:UP主信息 -->
<div class="flex items-center gap-3">
<img
@click="router.push(`/otherUserPage/${videoDetail?.createUserId}/0`)"
@click="jumpToUserHomePage({ userId: videoDetail?.createUserId, isReal: 0 })"
:src="videoDetail?.createUserAvatar"
class="w-12 h-12 rounded-full object-cover cursor-pointer hover:opacity-80 transition-opacity ring-2 ring-gray-100"
/>
......@@ -243,9 +243,9 @@ import type { ArticleItemDto } from '@/api/article/types'
import Comment from '@/components/common/Comment/index.vue'
import RewardDialog from './components/rewardDialog.vue'
import ActionMore from '@/components/common/ActionMore/index.vue'
import { jumpToUserHomePage } from '@/utils'
const route = useRoute()
const router = useRouter()
const videoId = route.params.id as string
// 视频详情
......
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