Browse Source

feat: 章节默认打开功能和深度模式状态记忆

Mochocyang 3 months ago
parent
commit
3b077b4b3c

+ 16 - 2
src/App.tsx

@@ -4,8 +4,8 @@ import { useWikiStore } from "@/stores/wiki-store"
 import { useReviewStore } from "@/stores/review-store"
 import { useReviewStore } from "@/stores/review-store"
 import { isTauri, pickDirectory } from "@/lib/platform"
 import { isTauri, pickDirectory } from "@/lib/platform"
 import { useChatStore } from "@/stores/chat-store"
 import { useChatStore } from "@/stores/chat-store"
-import { listDirectory, openProject } from "@/commands/fs"
-import { getLastProject, saveLastProject, loadLlmConfig, loadAiChatModel, loadDefaultLlmModel, loadLanguage, loadEmbeddingConfig, loadProviderConfigs, loadActivePresetId, loadProxyConfig, loadScheduledImportConfig, saveScheduledImportConfig, loadSourceWatchConfig, loadNovelMode, loadNovelConfig, loadRevisionFeedbackWindowConfig, loadTheme, loadMaxHistoryMessages, saveLlmConfig } from "@/lib/project-store"
+import { listDirectory, openProject, fileExists } from "@/commands/fs"
+import { getLastProject, saveLastProject, loadLlmConfig, loadAiChatModel, loadDefaultLlmModel, loadLanguage, loadEmbeddingConfig, loadProviderConfigs, loadActivePresetId, loadProxyConfig, loadScheduledImportConfig, saveScheduledImportConfig, loadSourceWatchConfig, loadNovelMode, loadNovelConfig, loadRevisionFeedbackWindowConfig, loadTheme, loadMaxHistoryMessages, saveLlmConfig, loadLastReadChapter } from "@/lib/project-store"
 import { loadReviewItems, loadChatHistory, saveChatHistory, saveReviewItems } from "@/lib/persist"
 import { loadReviewItems, loadChatHistory, saveChatHistory, saveReviewItems } from "@/lib/persist"
 import { setupAutoSave, teardownAutoSave } from "@/lib/auto-save"
 import { setupAutoSave, teardownAutoSave } from "@/lib/auto-save"
 import { checkForAppUpdate } from "@/lib/app-updater"
 import { checkForAppUpdate } from "@/lib/app-updater"
@@ -225,6 +225,20 @@ function App() {
     useWikiStore.getState().bumpDataVersion()
     useWikiStore.getState().bumpDataVersion()
     await saveLastProject(proj)
     await saveLastProject(proj)
 
 
+    // 自动打开最后阅读的章节和AI会话窗口
+    try {
+      const lastChapterPath = await loadLastReadChapter()
+      if (lastChapterPath) {
+        const exists = await fileExists(lastChapterPath)
+        if (exists) {
+          setSelectedFile(lastChapterPath)
+        }
+      }
+    } catch (err) {
+      console.error("加载最后阅读章节失败:", err)
+    }
+    useWikiStore.getState().setChatExpanded(true)
+
     if (isTauri()) {
     if (isTauri()) {
       try {
       try {
         await restoreIngestQueue(proj.id, proj.path)
         await restoreIngestQueue(proj.id, proj.path)

+ 2 - 1
src/components/chat/chat-panel.tsx

@@ -217,7 +217,8 @@ export function ChatPanel() {
   const [chapterSaveStatus, setChapterSaveStatus] = useState<string>("")
   const [chapterSaveStatus, setChapterSaveStatus] = useState<string>("")
   const [isSavingChapter, setIsSavingChapter] = useState(false)
   const [isSavingChapter, setIsSavingChapter] = useState(false)
   const [pendingSoulDialog, setPendingSoulDialog] = useState({ open: false, summary: "" })
   const [pendingSoulDialog, setPendingSoulDialog] = useState({ open: false, summary: "" })
-  const [deepChapterEnabled, setDeepChapterEnabled] = useState(false)
+  const deepChapterEnabled = useWikiStore((s) => s.deepChapterEnabled)
+  const setDeepChapterEnabled = useWikiStore((s) => s.setDeepChapterEnabled)
   // 故事框架绑定状态
   // 故事框架绑定状态
   const [activeBinding, setActiveBinding] = useState<{ binding: FrameworkBinding; framework: StoryFramework } | null>(null)
   const [activeBinding, setActiveBinding] = useState<{ binding: FrameworkBinding; framework: StoryFramework } | null>(null)
   const closeSoulDialog = useCallback((confirmed: boolean) => {
   const closeSoulDialog = useCallback((confirmed: boolean) => {

+ 3 - 0
src/components/layout/knowledge-tree.tsx

@@ -13,6 +13,7 @@ import { normalizeChapterStatus, type ChapterStatus } from "@/lib/novel/chapter-
 import { moveFileToTrash } from "@/lib/trash"
 import { moveFileToTrash } from "@/lib/trash"
 import { makeChapterFileName, makeDefaultChapterTitle, makeSafeFileSlug } from "@/lib/wiki-filename"
 import { makeChapterFileName, makeDefaultChapterTitle, makeSafeFileSlug } from "@/lib/wiki-filename"
 import { useImportProgressStore } from "@/stores/import-progress-store"
 import { useImportProgressStore } from "@/stores/import-progress-store"
+import { saveLastReadChapter } from "@/lib/project-store"
 
 
 interface WikiPageInfo {
 interface WikiPageInfo {
   path: string
   path: string
@@ -829,6 +830,8 @@ export function KnowledgeTree({
     setArmedPath(null)
     setArmedPath(null)
     if (renamingPath === pagePath) return
     if (renamingPath === pagePath) return
     setSelectedFile(pagePath)
     setSelectedFile(pagePath)
+    // 保存最后阅读的章节路径,用于启动时自动打开
+    saveLastReadChapter(pagePath).catch(() => {})
   }, [renamingPath, setSelectedFile])
   }, [renamingPath, setSelectedFile])
 
 
   const toggleFolder = useCallback((folderPath: string) => {
   const toggleFolder = useCallback((folderPath: string) => {

+ 13 - 0
src/lib/project-store.ts

@@ -652,3 +652,16 @@ function normalizeRerankConfig(
     maxCandidates: Math.max(3, Math.min(30, config.maxCandidates ?? DEFAULT_RERANK_CONFIG.maxCandidates)),
     maxCandidates: Math.max(3, Math.min(30, config.maxCandidates ?? DEFAULT_RERANK_CONFIG.maxCandidates)),
   }
   }
 }
 }
+
+const LAST_READ_CHAPTER_KEY = "lastReadChapter"
+
+export async function saveLastReadChapter(chapterPath: string): Promise<void> {
+  const store = await getStore()
+  await store.set(LAST_READ_CHAPTER_KEY, chapterPath)
+}
+
+export async function loadLastReadChapter(): Promise<string | null> {
+  const store = await getStore()
+  const path = await store.get<string>(LAST_READ_CHAPTER_KEY)
+  return path ?? null
+}

+ 5 - 0
src/stores/wiki-store.ts

@@ -518,6 +518,8 @@ interface WikiState {
   sourceWatchConfig: SourceWatchConfig
   sourceWatchConfig: SourceWatchConfig
   novelMode: boolean
   novelMode: boolean
   chatEditModeEnabled: boolean
   chatEditModeEnabled: boolean
+  /** 深度模式状态:跨视图切换保持开启 */
+  deepChapterEnabled: boolean
   novelConfig: NovelConfig
   novelConfig: NovelConfig
   /** 社区摘要生成错误信息(UI 层监听并弹窗提示) */
   /** 社区摘要生成错误信息(UI 层监听并弹窗提示) */
   communitySummaryError: string | null
   communitySummaryError: string | null
@@ -578,6 +580,7 @@ interface WikiState {
   setSourceWatchConfig: (sourceWatchConfig: SourceWatchConfig) => void
   setSourceWatchConfig: (sourceWatchConfig: SourceWatchConfig) => void
   setNovelMode: (novelMode: boolean) => void
   setNovelMode: (novelMode: boolean) => void
   setChatEditModeEnabled: (enabled: boolean) => void
   setChatEditModeEnabled: (enabled: boolean) => void
+  setDeepChapterEnabled: (enabled: boolean) => void
   setNovelConfig: (config: Partial<NovelConfig>) => void
   setNovelConfig: (config: Partial<NovelConfig>) => void
   setCommunitySummaryError: (error: string | null) => void
   setCommunitySummaryError: (error: string | null) => void
   setSearchHistory: (history: string[]) => void
   setSearchHistory: (history: string[]) => void
@@ -739,6 +742,7 @@ export const useWikiStore = create<WikiState>((set) => ({
 
 
   novelMode: true,
   novelMode: true,
   chatEditModeEnabled: false,
   chatEditModeEnabled: false,
+  deepChapterEnabled: false,
   novelConfig: { ...DEFAULT_NOVEL_CONFIG },
   novelConfig: { ...DEFAULT_NOVEL_CONFIG },
   communitySummaryError: null,
   communitySummaryError: null,
   searchHistory: [],
   searchHistory: [],
@@ -770,6 +774,7 @@ export const useWikiStore = create<WikiState>((set) => ({
   setSourceWatchConfig: (sourceWatchConfig) => set({ sourceWatchConfig }),
   setSourceWatchConfig: (sourceWatchConfig) => set({ sourceWatchConfig }),
   setNovelMode: (novelMode) => set({ novelMode }),
   setNovelMode: (novelMode) => set({ novelMode }),
   setChatEditModeEnabled: (chatEditModeEnabled) => set({ chatEditModeEnabled }),
   setChatEditModeEnabled: (chatEditModeEnabled) => set({ chatEditModeEnabled }),
+  setDeepChapterEnabled: (deepChapterEnabled) => set({ deepChapterEnabled }),
   setNovelConfig: (config) => set((state) => ({ novelConfig: { ...state.novelConfig, ...config } })),
   setNovelConfig: (config) => set((state) => ({ novelConfig: { ...state.novelConfig, ...config } })),
   setCommunitySummaryError: (communitySummaryError) => set({ communitySummaryError }),
   setCommunitySummaryError: (communitySummaryError) => set({ communitySummaryError }),
   setSearchHistory: (searchHistory) => set({ searchHistory }),
   setSearchHistory: (searchHistory) => set({ searchHistory }),