Commit 861e50b6 by lijiabin

【需求 25171】feat: 发布/编辑页新增预览功能,问吧问题卡片抽成共用组件

parent 82d62658
...@@ -95,6 +95,7 @@ ...@@ -95,6 +95,7 @@
alt="" alt=""
class="w-12 h-12 rounded-full object-cover cursor-pointer" class="w-12 h-12 rounded-full object-cover cursor-pointer"
@click=" @click="
!isPreview &&
jumpToUserHomePage({ jumpToUserHomePage({
userId: articleDetail.createUserId, userId: articleDetail.createUserId,
type: articleDetail.type, type: articleDetail.type,
...@@ -163,7 +164,7 @@ ...@@ -163,7 +164,7 @@
{{ articleType }} {{ articleType }}
</span> </span>
<ActionMore :articleDetail="articleDetail" /> <ActionMore v-if="!isPreview" :articleDetail="articleDetail" />
</div> </div>
</div> </div>
</div> </div>
...@@ -305,9 +306,10 @@ const userStore = useUserStore() ...@@ -305,9 +306,10 @@ const userStore = useUserStore()
const { userInfo } = storeToRefs(userStore) const { userInfo } = storeToRefs(userStore)
const router = useRouter() const router = useRouter()
const { jumpToUserHomePage } = useNavigation() const { jumpToUserHomePage } = useNavigation()
const { articleDetail, isAudit } = defineProps<{ const { articleDetail, isAudit, isPreview = false } = defineProps<{
articleDetail: ArticleItemDto articleDetail: ArticleItemDto
isAudit: boolean // 是否是审核页面 isAudit: boolean // 是否是审核页面
isPreview?: boolean // 是否是发布页的预览:数据是前端拼的,头像不跳转、不展示举报
}>() }>()
const sendMessageDialogRef = ref<InstanceType<typeof SendMessageDialog> | null>(null) const sendMessageDialogRef = ref<InstanceType<typeof SendMessageDialog> | null>(null)
......
<template> <template>
<div class="min-h-screen bg-gradient-to-br pb-10 relative"> <div class="min-h-screen bg-gradient-to-br pb-10 relative">
<BackButton /> <BackButton />
<!-- 主编辑区域 --> <!-- 主编辑区域:预览时用 v-show 藏起来而不是销毁,返回编辑时编辑器里的内容和光标状态都还在 -->
<div class="bg-white rounded-lg shadow-lg border border-gray-100/50 overflow-hidden"> <div
v-show="!previewing"
class="bg-white rounded-lg shadow-lg border border-gray-100/50 overflow-hidden"
>
<div class="px-10 py-5"> <div class="px-10 py-5">
<!-- 标题输入 --> <!-- 标题输入 -->
<el-form-item class="mb-8"> <el-form-item class="mb-8">
...@@ -41,11 +44,21 @@ ...@@ -41,11 +44,21 @@
</div> </div>
<!-- 底部固定按钮栏 --> <!-- 底部固定按钮栏 -->
<div class="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-200 shadow-lg"> <div
v-show="!previewing"
class="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-200 shadow-lg"
>
<div class="max-w-[1200px] mx-auto px-4 py-3"> <div class="max-w-[1200px] mx-auto px-4 py-3">
<div class="flex justify-center gap-4"> <div class="flex justify-center gap-4">
<el-button @click="handleClosed" class="rounded-lg min-w[120px]"> 取消 </el-button> <el-button @click="handleClosed" class="rounded-lg min-w[120px]"> 取消 </el-button>
<el-button <el-button
:disabled="!sharedForm.content"
@click="previewing = true"
class="rounded-lg min-w[120px]"
>
预览
</el-button>
<el-button
type="primary" type="primary"
:disabled="!canPublish" :disabled="!canPublish"
@click="openDrawer" @click="openDrawer"
...@@ -89,6 +102,7 @@ ...@@ -89,6 +102,7 @@
<template #footer> <template #footer>
<div class="flex gap-3 justify-end"> <div class="flex gap-3 justify-end">
<el-button @click="handleDrawerClose" class="rounded-lg">取消</el-button> <el-button @click="handleDrawerClose" class="rounded-lg">取消</el-button>
<el-button @click="handlePreviewFromDrawer" class="rounded-lg">预览</el-button>
<el-button <el-button
:loading="loading" :loading="loading"
@click="handleSubmit(ReleaseStatusTypeEnum.DRAFT)" @click="handleSubmit(ReleaseStatusTypeEnum.DRAFT)"
...@@ -107,6 +121,19 @@ ...@@ -107,6 +121,19 @@
</div> </div>
</template> </template>
</el-drawer> </el-drawer>
<!-- 预览:直接用详情页的 ArticleContent 渲染,所见即所得,不用先保存也不需要接口 -->
<div v-if="previewing" class="space-y-4">
<!-- 问吧详情页的样子跟其它图文类完全不同,用它自己的问题卡片;其它类型用 ArticleContent -->
<QuestionCard v-if="type === ArticleTypeEnum.QUESTION" :questionDetail="previewDetail" isPreview />
<ArticleContent v-else :articleDetail="previewDetail" :isAudit="true" :isPreview="true" />
<div class="flex justify-end gap-3">
<el-button @click="previewing = false">返回编辑</el-button>
<el-button type="primary" :disabled="!canPublish" @click="openDrawer">
{{ isEdit ? '编辑' : '发布' }}
</el-button>
</div>
</div>
</div> </div>
</template> </template>
...@@ -132,6 +159,10 @@ import type { ArticleItemDto } from '@/api' ...@@ -132,6 +159,10 @@ import type { ArticleItemDto } from '@/api'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import { push } from 'notivue' import { push } from 'notivue'
import BackButton from '@/components/common/BackButton/index.vue' import BackButton from '@/components/common/BackButton/index.vue'
import ArticleContent from '@/components/common/ArticleContent/index.vue'
import QuestionCard from '@/components/common/QuestionCard/index.vue'
import { useUserStore } from '@/stores/user'
import { storeToRefs } from 'pinia'
import type { ArticleTypeFormExpose } from './types' import type { ArticleTypeFormExpose } from './types'
import PostForm from './components/PostForm.vue' import PostForm from './components/PostForm.vue'
import ColumnForm from './components/ColumnForm.vue' import ColumnForm from './components/ColumnForm.vue'
...@@ -183,6 +214,39 @@ const handleDrawerClose = () => { ...@@ -183,6 +214,39 @@ const handleDrawerClose = () => {
drawerVisible.value = false drawerVisible.value = false
} }
// 预览:用当前编辑器里的标题/内容和自己的头像昵称拼一份假的文章详情,交给 ArticleContent 渲染。
// 标签、浏览量这些要后端数据的部分预览里没有,也不需要
const previewing = ref(false)
const userStore = useUserStore()
const { userInfo } = storeToRefs(userStore)
// 抽屉里也能预览:关掉抽屉进预览,抽屉里已填的内容不会丢(子表单没销毁),预览里点发布会再打开
const handlePreviewFromDrawer = () => {
drawerVisible.value = false
previewing.value = true
}
const previewDetail = computed(() => {
// 实践/问吧的配图在抽屉子表单里,拿得到就带上
const imgUrl = subFormRef.value?.getSubmitData().imgUrl as string | undefined
const isReal = [
ArticleTypeEnum.PRACTICE,
ArticleTypeEnum.INTERVIEW,
ArticleTypeEnum.QUESTION,
].includes(type)
return {
type,
title: sharedForm.value.title,
content: sharedForm.value.content,
imgUrl,
imgUrlList: imgUrl?.split(',').filter(Boolean) ?? [],
createTime: Math.floor(Date.now() / 1000),
viewCount: 0,
createUserName: isReal ? userInfo.value.name : userInfo.value.hiddenName,
createUserAvatar: isReal ? userInfo.value.avatar : userInfo.value.hiddenAvatar,
tagNameList: [],
tagIdList: [],
} as unknown as ArticleItemDto
})
// 取消按钮 // 取消按钮
const handleClosed = () => { const handleClosed = () => {
resetSharedForm() resetSharedForm()
...@@ -228,6 +292,7 @@ const editorKey = ref(0) ...@@ -228,6 +292,7 @@ const editorKey = ref(0)
const isEdit = computed(() => !!route.query.id) const isEdit = computed(() => !!route.query.id)
onActivated(async () => { onActivated(async () => {
previewing.value = false
editorKey.value++ editorKey.value++
resetSharedForm() resetSharedForm()
subFormRef.value?.reset() subFormRef.value?.reset()
......
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