fix(frontend): 防止切换文件丢稿并修复主题恢复
This commit is contained in:
@@ -53,8 +53,8 @@ async function createNote() {
|
||||
const name = rawName.endsWith('.md') ? rawName : `${rawName}.md`
|
||||
const file = await workspaceService.createFile('/', name, `# ${rawName}\n\n`)
|
||||
workspaceStore.addFileToTree('/', file)
|
||||
workspaceStore.openFile(file.path)
|
||||
await editorStore.loadFile(file.path)
|
||||
workspaceStore.openFile(file.path)
|
||||
await router.push('/workspace')
|
||||
}
|
||||
|
||||
|
||||
@@ -41,8 +41,8 @@ watch(() => chatStore.selectedProviderId, async (providerId) => {
|
||||
function send() { void chatStore.sendMessage(chatStore.inputText) }
|
||||
|
||||
async function openCitation(citation: Citation) {
|
||||
workspaceStore.openFile(citation.file_path)
|
||||
await editorStore.loadFile(citation.file_path)
|
||||
workspaceStore.openFile(citation.file_path)
|
||||
editorStore.highlightBlock(citation.block_id)
|
||||
await router.push('/workspace')
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ function submitSearch() {
|
||||
}
|
||||
|
||||
async function openResult(result: SearchResult) {
|
||||
workspaceStore.openFile(result.file_path)
|
||||
await editorStore.loadFile(result.file_path)
|
||||
workspaceStore.openFile(result.file_path)
|
||||
editorStore.highlightBlock(result.block_id)
|
||||
await router.push('/workspace')
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ async function createItem() {
|
||||
const name = rawName.endsWith('.md') ? rawName : `${rawName}.md`
|
||||
const file = await workspaceService.createFile(parentPath.value, name, `# ${rawName}\n\n`)
|
||||
workspaceStore.addFileToTree(parentPath.value, file)
|
||||
workspaceStore.openFile(file.path)
|
||||
await editorStore.loadFile(file.path)
|
||||
workspaceStore.openFile(file.path)
|
||||
await router.push('/workspace')
|
||||
} else {
|
||||
const folder = await workspaceService.createFolder(parentPath.value, rawName)
|
||||
@@ -42,8 +42,8 @@ async function createItem() {
|
||||
|
||||
async function openNode(node: FileNode) {
|
||||
if (node.type === 'folder') return workspaceStore.toggleFolder(node.path)
|
||||
workspaceStore.openFile(node.path)
|
||||
await editorStore.loadFile(node.path)
|
||||
workspaceStore.openFile(node.path)
|
||||
await router.push('/workspace')
|
||||
}
|
||||
|
||||
@@ -80,8 +80,8 @@ async function deleteTarget() {
|
||||
const activeWasRemoved = workspaceStore.closePath(node.path)
|
||||
workspaceStore.removeFromTree(node.path)
|
||||
if (activeWasRemoved) {
|
||||
editorStore.closeFile()
|
||||
if (workspaceStore.activeFilePath) await editorStore.loadFile(workspaceStore.activeFilePath)
|
||||
else editorStore.closeFile()
|
||||
}
|
||||
closeContextMenu()
|
||||
}
|
||||
|
||||
@@ -13,8 +13,9 @@ onMounted(() => {
|
||||
// Already loaded
|
||||
}
|
||||
if (!workspaceStore.activeFilePath && workspaceStore.fileTree.length === 0) {
|
||||
workspaceStore.openFile('/欢迎使用知笔知己.md')
|
||||
editorStore.loadFile('/欢迎使用知笔知己.md')
|
||||
void editorStore.loadFile('/欢迎使用知笔知己.md').then(() => {
|
||||
workspaceStore.openFile('/欢迎使用知笔知己.md')
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -34,34 +34,54 @@ export const useEditorStore = defineStore('editor', () => {
|
||||
}
|
||||
|
||||
let saveTimer: ReturnType<typeof setTimeout> | null = null
|
||||
let pendingSave: Promise<void> | null = null
|
||||
|
||||
function scheduleAutoSave(delay = 1500) {
|
||||
if (saveTimer) clearTimeout(saveTimer)
|
||||
saveTimer = setTimeout(() => {
|
||||
saveTimer = null
|
||||
void save()
|
||||
}, delay)
|
||||
}
|
||||
|
||||
async function save() {
|
||||
if (!currentFilePath.value) return
|
||||
if (saveStatus.value === 'saving') return
|
||||
if (pendingSave) return pendingSave
|
||||
const targetPath = currentFilePath.value
|
||||
const snapshot = content.value
|
||||
saveStatus.value = 'saving'
|
||||
try {
|
||||
await workspaceService.saveFileContent(targetPath, snapshot)
|
||||
if (currentFilePath.value === targetPath) {
|
||||
saveStatus.value = content.value === snapshot ? 'saved' : 'dirty'
|
||||
lastSavedAt.value = new Date().toISOString()
|
||||
pendingSave = (async () => {
|
||||
try {
|
||||
await workspaceService.saveFileContent(targetPath, snapshot)
|
||||
if (currentFilePath.value === targetPath) {
|
||||
saveStatus.value = content.value === snapshot ? 'saved' : 'dirty'
|
||||
lastSavedAt.value = new Date().toISOString()
|
||||
}
|
||||
} catch {
|
||||
if (currentFilePath.value === targetPath) saveStatus.value = 'save_failed'
|
||||
} finally {
|
||||
pendingSave = null
|
||||
}
|
||||
} catch {
|
||||
saveStatus.value = 'save_failed'
|
||||
}
|
||||
})()
|
||||
return pendingSave
|
||||
}
|
||||
|
||||
let loadVersion = 0
|
||||
|
||||
async function loadFile(filePath: string) {
|
||||
if (currentFilePath.value === filePath) return
|
||||
if (saveTimer) {
|
||||
clearTimeout(saveTimer)
|
||||
saveTimer = null
|
||||
}
|
||||
if (saveStatus.value === 'conflict') {
|
||||
throw new Error('当前文件存在编辑冲突,请处理后再切换文件。')
|
||||
}
|
||||
if (pendingSave) await pendingSave
|
||||
if (saveStatus.value === 'dirty' || saveStatus.value === 'save_failed') await save()
|
||||
if (saveStatus.value === 'dirty' || saveStatus.value === 'save_failed') {
|
||||
throw new Error('当前文件保存失败,已阻止切换以避免内容丢失。')
|
||||
}
|
||||
const version = ++loadVersion
|
||||
currentFilePath.value = filePath
|
||||
saveStatus.value = 'saving'
|
||||
|
||||
@@ -14,6 +14,7 @@ export const useThemeStore = defineStore('theme', () => {
|
||||
const fontEditorSize = ref(15)
|
||||
const fontEditorFamily = ref('system-ui')
|
||||
const lineHeight = ref(1.7)
|
||||
let appearanceHydrated = false
|
||||
|
||||
const currentTheme = computed(() =>
|
||||
themes.value.find((t) => t.theme_id === currentThemeId.value) || themes.value[0]
|
||||
@@ -47,6 +48,8 @@ export const useThemeStore = defineStore('theme', () => {
|
||||
} catch { localStorage.removeItem('editor-appearance') }
|
||||
}
|
||||
const saved = localStorage.getItem('theme')
|
||||
appearanceHydrated = true
|
||||
persistAppearance()
|
||||
if (saved && themes.value.find((t) => t.theme_id === saved)) {
|
||||
applyTheme(saved)
|
||||
return
|
||||
@@ -72,17 +75,17 @@ export const useThemeStore = defineStore('theme', () => {
|
||||
|
||||
watch(fontEditorSize, (v) => {
|
||||
document.documentElement.style.setProperty('--font-editor-size', `${v}px`)
|
||||
persistAppearance()
|
||||
if (appearanceHydrated) persistAppearance()
|
||||
}, { immediate: true })
|
||||
|
||||
watch(lineHeight, (v) => {
|
||||
document.documentElement.style.setProperty('--font-editor-line-height', String(v))
|
||||
persistAppearance()
|
||||
if (appearanceHydrated) persistAppearance()
|
||||
}, { immediate: true })
|
||||
|
||||
watch(fontEditorFamily, (v) => {
|
||||
document.documentElement.style.setProperty('--font-editor-sans', v)
|
||||
persistAppearance()
|
||||
if (appearanceHydrated) persistAppearance()
|
||||
}, { immediate: true })
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user