引入二级大纲功能,新增父子节点关系及子节点排序,同时调整API与UI以支持嵌套大纲管理
This commit is contained in:
91
frontend/src/views/NovelWorkspace.vue
Normal file
91
frontend/src/views/NovelWorkspace.vue
Normal file
@@ -0,0 +1,91 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, provide } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { fetchNovel } from '@/api/novels'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
import type { Novel } from '@/types/novel'
|
||||
import NovelSubNav from '@/components/novel/NovelSubNav.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const toast = useToast()
|
||||
|
||||
const novelId = Number(route.params.id)
|
||||
const novel = ref<Novel | null>(null)
|
||||
const loading = ref(true)
|
||||
|
||||
/** 子页面可设置的副标题(如 "共 5 个节点") */
|
||||
const subtitle = ref('')
|
||||
|
||||
async function load() {
|
||||
loading.value = true
|
||||
try {
|
||||
novel.value = await fetchNovel(novelId)
|
||||
} catch {
|
||||
toast.error('作品不存在')
|
||||
router.push({ name: 'home' })
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 提供给子路由
|
||||
provide('workspace-novel', novel)
|
||||
provide('workspace-novel-id', novelId)
|
||||
provide('workspace-subtitle', subtitle)
|
||||
|
||||
onMounted(load)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="!loading && novel" class="workspace">
|
||||
<NovelSubNav
|
||||
:novel-id="novelId"
|
||||
:novel-title="novel.title"
|
||||
:subtitle="subtitle"
|
||||
>
|
||||
<template #actions>
|
||||
<!-- 子页面通过 Teleport 注入操作按钮 -->
|
||||
<div id="workspace-actions" />
|
||||
</template>
|
||||
</NovelSubNav>
|
||||
|
||||
<div class="workspace-content">
|
||||
<RouterView />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="loading" class="workspace-loading">
|
||||
<div class="loading-pulse" style="height: 1.5rem; width: 30%; margin-bottom: var(--space-md)" />
|
||||
<div class="loading-pulse" style="height: 1rem; width: 60%; margin-bottom: var(--space-2xl)" />
|
||||
<div class="loading-pulse" style="height: 20rem; width: 100%" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.workspace {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.workspace-content {
|
||||
animation: fadeInUp var(--duration-normal) var(--ease-out-smooth) both;
|
||||
}
|
||||
|
||||
.workspace-loading {
|
||||
max-width: 900px;
|
||||
margin: var(--space-3xl) auto;
|
||||
}
|
||||
|
||||
.loading-pulse {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
var(--paper-100) 25%,
|
||||
var(--paper-200) 50%,
|
||||
var(--paper-100) 75%
|
||||
);
|
||||
background-size: 200% 100%;
|
||||
border-radius: var(--radius-sm);
|
||||
animation: shimmer 1.5s ease infinite;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user