fix(frontend): 接通设置状态与搜索降级
This commit is contained in:
@@ -2,6 +2,12 @@ import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import type { SearchResult, SearchRequest } from '@/contracts'
|
||||
import * as searchService from '@/services/searchService'
|
||||
import { ApiErrorClass } from '@/services/apiClient'
|
||||
|
||||
const VECTOR_ERROR_CODES = new Set([
|
||||
'VECTOR_UNAVAILABLE', 'EMBEDDING_UNAVAILABLE', 'INDEX_UNAVAILABLE',
|
||||
'MODEL_NOT_FOUND', 'MODEL_CAPABILITY_MISMATCH', 'PROVIDER_UNAVAILABLE',
|
||||
])
|
||||
|
||||
export const useSearchStore = defineStore('search', () => {
|
||||
const query = ref('')
|
||||
@@ -19,16 +25,33 @@ export const useSearchStore = defineStore('search', () => {
|
||||
mode.value = request.mode || 'hybrid'
|
||||
isSearching.value = true
|
||||
error.value = null
|
||||
vectorUnavailable.value = false
|
||||
|
||||
try {
|
||||
const resp = await searchService.search(request)
|
||||
results.value = resp.results
|
||||
total.value = resp.total
|
||||
selectedIndex.value = 0
|
||||
} catch (e: any) {
|
||||
error.value = e.message || '搜索失败'
|
||||
results.value = []
|
||||
total.value = 0
|
||||
} catch (reason) {
|
||||
const canFallback = mode.value !== 'fts' && reason instanceof ApiErrorClass && VECTOR_ERROR_CODES.has(reason.code)
|
||||
if (canFallback) {
|
||||
try {
|
||||
const fallback = await searchService.search({ ...request, mode: 'fts' })
|
||||
results.value = fallback.results
|
||||
total.value = fallback.total
|
||||
mode.value = 'fts'
|
||||
vectorUnavailable.value = true
|
||||
selectedIndex.value = 0
|
||||
} catch (fallbackError) {
|
||||
error.value = fallbackError instanceof Error ? fallbackError.message : '全文检索降级失败'
|
||||
results.value = []
|
||||
total.value = 0
|
||||
}
|
||||
} else {
|
||||
error.value = reason instanceof Error ? reason.message : '搜索失败'
|
||||
results.value = []
|
||||
total.value = 0
|
||||
}
|
||||
} finally {
|
||||
isSearching.value = false
|
||||
}
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { ref, watch } from 'vue'
|
||||
import type { AiCoreStatus, IndexStatus } from '@/contracts'
|
||||
import { mockIndexStatus } from '@/services/indexService'
|
||||
import * as indexService from '@/services/indexService'
|
||||
import * as systemService from '@/services/systemService'
|
||||
|
||||
export const useSettingsStore = defineStore('settings', () => {
|
||||
const saved = (() => {
|
||||
try { return JSON.parse(localStorage.getItem('app-settings') ?? '{}') as Record<string, unknown> }
|
||||
catch { localStorage.removeItem('app-settings'); return {} }
|
||||
})()
|
||||
// General
|
||||
const restoreLastVault = ref(true)
|
||||
const autoSaveInterval = ref(1500)
|
||||
const language = ref<'zh-CN' | 'en'>('zh-CN')
|
||||
const restoreLastVault = ref(saved.restoreLastVault !== false)
|
||||
const autoSaveInterval = ref(typeof saved.autoSaveInterval === 'number' ? saved.autoSaveInterval : 1500)
|
||||
const language = ref<'zh-CN' | 'en'>(saved.language === 'en' ? 'en' : 'zh-CN')
|
||||
const appVersion = ref('0.1.0')
|
||||
const aiCoreVersion = ref('0.1.0')
|
||||
|
||||
// Editor
|
||||
const defaultEditorMode = ref<'wysiwyg' | 'source'>('wysiwyg')
|
||||
const editorFontSize = ref(15)
|
||||
const editorLineHeight = ref(1.7)
|
||||
const editorLineWidth = ref(80)
|
||||
const spellCheck = ref(false)
|
||||
const defaultEditorMode = ref<'wysiwyg' | 'source'>(saved.defaultEditorMode === 'source' ? 'source' : 'wysiwyg')
|
||||
const editorLineWidth = ref(typeof saved.editorLineWidth === 'number' ? saved.editorLineWidth : 80)
|
||||
const spellCheck = ref(saved.spellCheck === true)
|
||||
|
||||
// AI Core
|
||||
const aiCoreStatus = ref<AiCoreStatus>('running')
|
||||
@@ -41,6 +43,12 @@ export const useSettingsStore = defineStore('settings', () => {
|
||||
})
|
||||
const diagnosticsError = ref<string | null>(null)
|
||||
|
||||
watch(() => ({
|
||||
restoreLastVault: restoreLastVault.value, autoSaveInterval: autoSaveInterval.value,
|
||||
language: language.value, defaultEditorMode: defaultEditorMode.value,
|
||||
editorLineWidth: editorLineWidth.value, spellCheck: spellCheck.value,
|
||||
}), (value) => localStorage.setItem('app-settings', JSON.stringify(value)), { deep: true })
|
||||
|
||||
async function loadDiagnostics() {
|
||||
try {
|
||||
const [health, status, index] = await Promise.all([
|
||||
@@ -97,8 +105,6 @@ export const useSettingsStore = defineStore('settings', () => {
|
||||
appVersion,
|
||||
aiCoreVersion,
|
||||
defaultEditorMode,
|
||||
editorFontSize,
|
||||
editorLineHeight,
|
||||
editorLineWidth,
|
||||
spellCheck,
|
||||
aiCoreStatus,
|
||||
|
||||
@@ -37,6 +37,15 @@ export const useThemeStore = defineStore('theme', () => {
|
||||
}
|
||||
|
||||
function initTheme() {
|
||||
const savedAppearance = localStorage.getItem('editor-appearance')
|
||||
if (savedAppearance) {
|
||||
try {
|
||||
const value = JSON.parse(savedAppearance) as { size?: number; family?: string; lineHeight?: number }
|
||||
if (value.size) fontEditorSize.value = value.size
|
||||
if (value.family) fontEditorFamily.value = value.family
|
||||
if (value.lineHeight) lineHeight.value = value.lineHeight
|
||||
} catch { localStorage.removeItem('editor-appearance') }
|
||||
}
|
||||
const saved = localStorage.getItem('theme')
|
||||
if (saved && themes.value.find((t) => t.theme_id === saved)) {
|
||||
applyTheme(saved)
|
||||
@@ -57,13 +66,24 @@ export const useThemeStore = defineStore('theme', () => {
|
||||
lineHeight.value = 1.7
|
||||
}
|
||||
|
||||
const persistAppearance = () => localStorage.setItem('editor-appearance', JSON.stringify({
|
||||
size: fontEditorSize.value, family: fontEditorFamily.value, lineHeight: lineHeight.value,
|
||||
}))
|
||||
|
||||
watch(fontEditorSize, (v) => {
|
||||
document.documentElement.style.setProperty('--font-editor-size', `${v}px`)
|
||||
})
|
||||
persistAppearance()
|
||||
}, { immediate: true })
|
||||
|
||||
watch(lineHeight, (v) => {
|
||||
document.documentElement.style.setProperty('--font-editor-line-height', String(v))
|
||||
})
|
||||
persistAppearance()
|
||||
}, { immediate: true })
|
||||
|
||||
watch(fontEditorFamily, (v) => {
|
||||
document.documentElement.style.setProperty('--font-editor-sans', v)
|
||||
persistAppearance()
|
||||
}, { immediate: true })
|
||||
|
||||
return {
|
||||
themes,
|
||||
|
||||
Reference in New Issue
Block a user