引入二级大纲功能,新增父子节点关系及子节点排序,同时调整API与UI以支持嵌套大纲管理
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { ref, inject, onMounted, computed } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { fetchNovel } from '@/api/novels'
|
||||
import { fetchWorldSetting, saveWorldSetting } from '@/api/worldSetting'
|
||||
import { useToast } from '@/composables/useToast'
|
||||
import { useToolRefresh } from '@/composables/useToolRefresh'
|
||||
import type { Novel } from '@/types/novel'
|
||||
import BaseButton from '@/components/ui/BaseButton.vue'
|
||||
import BaseTextarea from '@/components/ui/BaseTextarea.vue'
|
||||
@@ -12,8 +12,9 @@ const route = useRoute()
|
||||
const router = useRouter()
|
||||
const toast = useToast()
|
||||
|
||||
const novelId = Number(route.params.id)
|
||||
const novel = ref<Novel | null>(null)
|
||||
const novelId = inject<number>('workspace-novel-id', Number(route.params.id))
|
||||
const novel = inject<import('vue').Ref<Novel | null>>('workspace-novel', ref(null))
|
||||
const subtitle = inject<import('vue').Ref<string>>('workspace-subtitle', ref(''))
|
||||
const content = ref('')
|
||||
const loading = ref(true)
|
||||
const saving = ref(false)
|
||||
@@ -26,14 +27,16 @@ const contentHint = computed(() => {
|
||||
return `${contentLength.value} 字`
|
||||
})
|
||||
|
||||
// 世界观页不需要副标题
|
||||
subtitle.value = ''
|
||||
|
||||
// AI 工具执行后自动刷新世界观数据
|
||||
useToolRefresh(['get_world_setting', 'save_world_setting'], load)
|
||||
|
||||
async function load() {
|
||||
loading.value = true
|
||||
try {
|
||||
const [n, ws] = await Promise.all([
|
||||
fetchNovel(novelId),
|
||||
fetchWorldSetting(novelId),
|
||||
])
|
||||
novel.value = n
|
||||
const ws = await fetchWorldSetting(novelId)
|
||||
content.value = ws.content
|
||||
} catch {
|
||||
toast.error('加载失败')
|
||||
@@ -64,15 +67,8 @@ onMounted(load)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="!loading && novel" class="world-view">
|
||||
<div class="world-header">
|
||||
<BaseButton variant="ghost" @click="router.push({ name: 'novel-detail', params: { id: novelId } })">
|
||||
← 返回
|
||||
</BaseButton>
|
||||
<div class="header-center">
|
||||
<h1 class="world-title">{{ novel.title }}</h1>
|
||||
<p class="world-subtitle">世界观设定</p>
|
||||
</div>
|
||||
<div v-if="!loading" class="world-view">
|
||||
<Teleport to="#workspace-actions">
|
||||
<BaseButton
|
||||
variant="primary"
|
||||
:loading="saving"
|
||||
@@ -81,7 +77,7 @@ onMounted(load)
|
||||
>
|
||||
保存
|
||||
</BaseButton>
|
||||
</div>
|
||||
</Teleport>
|
||||
|
||||
<div class="editor-container">
|
||||
<div class="editor-hint">
|
||||
@@ -124,33 +120,6 @@ onMounted(load)
|
||||
animation: fadeInUp var(--duration-normal) var(--ease-out-smooth) both;
|
||||
}
|
||||
|
||||
.world-header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: var(--space-md);
|
||||
margin-bottom: var(--space-2xl);
|
||||
}
|
||||
|
||||
.header-center {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.world-title {
|
||||
font-family: var(--font-display);
|
||||
font-size: 1.8rem;
|
||||
font-weight: 700;
|
||||
color: var(--ink-900);
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.world-subtitle {
|
||||
font-size: 0.85rem;
|
||||
color: var(--ink-400);
|
||||
margin-top: var(--space-xs);
|
||||
}
|
||||
|
||||
.editor-container {
|
||||
background: var(--paper-50);
|
||||
border: 1px solid var(--paper-200);
|
||||
|
||||
Reference in New Issue
Block a user