mirror of
https://github.com/AstrBotDevs/AstrBot.git
synced 2026-08-31 01:40:25 +08:00
fix(kb): distinguish loading errors from empty states (#9578)
* fix(kb): distinguish loading errors from empty states * fix(kb): reset loading errors before retries
This commit is contained in:
@@ -4,6 +4,10 @@
|
||||
"breadcrumb": {
|
||||
"list": "Knowledge Bases"
|
||||
},
|
||||
"states": {
|
||||
"loadError": "Failed to load knowledge base details",
|
||||
"retry": "Retry"
|
||||
},
|
||||
"tabs": {
|
||||
"overview": "Overview",
|
||||
"documents": "Documents",
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
{
|
||||
"title": "Document Details",
|
||||
"backToKB": "Back to Knowledge Base",
|
||||
"states": {
|
||||
"loadError": "Failed to load document details",
|
||||
"chunksLoadError": "Failed to load chunks",
|
||||
"retry": "Retry"
|
||||
},
|
||||
"info": {
|
||||
"title": "Document Information",
|
||||
"name": "Document Name",
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
"documents": "Documents",
|
||||
"chunks": "Chunks",
|
||||
"sessionConfig": "Session Config",
|
||||
"initError": "Initialization Failed"
|
||||
"initError": "Initialization Failed",
|
||||
"retry": "Retry"
|
||||
},
|
||||
"card": {
|
||||
"edit": "Edit",
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
"breadcrumb": {
|
||||
"list": "Базы знаний"
|
||||
},
|
||||
"states": {
|
||||
"loadError": "Не удалось загрузить базу знаний",
|
||||
"retry": "Повторить"
|
||||
},
|
||||
"tabs": {
|
||||
"overview": "Обзор",
|
||||
"documents": "Документы",
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
{
|
||||
"title": "Просмотр документа",
|
||||
"backToKB": "К базе знаний",
|
||||
"states": {
|
||||
"loadError": "Не удалось загрузить документ",
|
||||
"chunksLoadError": "Не удалось загрузить фрагменты",
|
||||
"retry": "Повторить"
|
||||
},
|
||||
"info": {
|
||||
"title": "Информация о документе",
|
||||
"name": "Имя файла",
|
||||
@@ -52,4 +57,4 @@
|
||||
"vecDocId": "ID вектора",
|
||||
"close": "Закрыть"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
"documents": "док.",
|
||||
"chunks": "фрагм.",
|
||||
"sessionConfig": "Профиль",
|
||||
"initError": "Ошибка инициализации"
|
||||
"initError": "Ошибка инициализации",
|
||||
"retry": "Повторить"
|
||||
},
|
||||
"card": {
|
||||
"edit": "Изменить",
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
"breadcrumb": {
|
||||
"list": "知识库"
|
||||
},
|
||||
"states": {
|
||||
"loadError": "知识库详情加载失败",
|
||||
"retry": "重试"
|
||||
},
|
||||
"tabs": {
|
||||
"overview": "概览",
|
||||
"documents": "文档管理",
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
{
|
||||
"title": "文档详情",
|
||||
"backToKB": "返回知识库",
|
||||
"states": {
|
||||
"loadError": "文档详情加载失败",
|
||||
"chunksLoadError": "分块列表加载失败",
|
||||
"retry": "重试"
|
||||
},
|
||||
"info": {
|
||||
"title": "文档信息",
|
||||
"name": "文档名称",
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
"documents": "文档",
|
||||
"chunks": "分块",
|
||||
"sessionConfig": "会话配置",
|
||||
"initError": "初始化失败"
|
||||
"initError": "初始化失败",
|
||||
"retry": "重试"
|
||||
},
|
||||
"card": {
|
||||
"edit": "编辑",
|
||||
|
||||
@@ -18,6 +18,14 @@
|
||||
<v-progress-circular indeterminate color="primary" size="64" />
|
||||
</div>
|
||||
|
||||
<div v-else-if="loadError" class="loading-container">
|
||||
<v-icon size="72" color="error">mdi-alert-circle-outline</v-icon>
|
||||
<p class="mt-4 text-medium-emphasis">{{ t('states.loadError') }}</p>
|
||||
<v-btn class="mt-4" prepend-icon="mdi-refresh" color="primary" variant="tonal" @click="loadDocument">
|
||||
{{ t('states.retry') }}
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
<!-- 主内容 -->
|
||||
<div v-else class="document-content">
|
||||
<!-- 文档信息卡片 -->
|
||||
@@ -97,7 +105,16 @@
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text class="pa-0">
|
||||
<v-alert v-if="chunksLoadError" type="error" variant="tonal" class="ma-4">
|
||||
<div class="d-flex align-center justify-space-between ga-4">
|
||||
<span>{{ t('states.chunksLoadError') }}</span>
|
||||
<v-btn prepend-icon="mdi-refresh" variant="tonal" size="small" @click="loadChunks">
|
||||
{{ t('states.retry') }}
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-alert>
|
||||
<v-data-table
|
||||
v-else
|
||||
:headers="headers"
|
||||
:items="filteredChunks"
|
||||
:loading="loadingChunks"
|
||||
@@ -150,7 +167,7 @@
|
||||
|
||||
|
||||
<!-- 自定义分页器 -->
|
||||
<div v-if="!searchQuery && totalChunks > 0" class="pa-4 d-flex align-center justify-space-between">
|
||||
<div v-if="!chunksLoadError && !searchQuery && totalChunks > 0" class="pa-4 d-flex align-center justify-space-between">
|
||||
<div class="text-caption text-medium-emphasis">
|
||||
{{ t('chunks.showing') }} {{ (page - 1) * pageSize + 1 }} - {{ Math.min(page * pageSize, totalChunks) }} / {{ totalChunks }}
|
||||
</div>
|
||||
@@ -250,6 +267,8 @@ const docId = ref(route.params.docId as string)
|
||||
// 状态
|
||||
const loading = ref(true)
|
||||
const loadingChunks = ref(false)
|
||||
const loadError = ref(false)
|
||||
const chunksLoadError = ref(false)
|
||||
const document = ref<any>({})
|
||||
const chunks = ref<any[]>([])
|
||||
const searchQuery = ref('')
|
||||
@@ -293,14 +312,20 @@ const filteredChunks = computed(() => {
|
||||
// 加载文档详情
|
||||
const loadDocument = async () => {
|
||||
loading.value = true
|
||||
loadError.value = false
|
||||
try {
|
||||
const response = await knowledgeApi.document(kbId.value, docId.value)
|
||||
if (response.data.status === 'ok') {
|
||||
document.value = response.data.data
|
||||
loadError.value = false
|
||||
} else {
|
||||
loadError.value = true
|
||||
showSnackbar(response.data.message || t('states.loadError'), 'error')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load document:', error)
|
||||
showSnackbar('加载文档详情失败', 'error')
|
||||
loadError.value = true
|
||||
showSnackbar(t('states.loadError'), 'error')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
@@ -309,6 +334,7 @@ const loadDocument = async () => {
|
||||
// 加载分块列表
|
||||
const loadChunks = async () => {
|
||||
loadingChunks.value = true
|
||||
chunksLoadError.value = false
|
||||
try {
|
||||
const response = await knowledgeApi.chunks(kbId.value, {
|
||||
document_id: docId.value,
|
||||
@@ -318,10 +344,15 @@ const loadChunks = async () => {
|
||||
if (response.data.status === 'ok') {
|
||||
chunks.value = response.data.data.items || []
|
||||
totalChunks.value = response.data.data.total || 0
|
||||
chunksLoadError.value = false
|
||||
} else {
|
||||
chunksLoadError.value = true
|
||||
showSnackbar(response.data.message || t('states.chunksLoadError'), 'error')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load chunks:', error)
|
||||
showSnackbar('加载分块列表失败', 'error')
|
||||
chunksLoadError.value = true
|
||||
showSnackbar(t('states.chunksLoadError'), 'error')
|
||||
} finally {
|
||||
loadingChunks.value = false
|
||||
}
|
||||
|
||||
@@ -5,6 +5,14 @@
|
||||
<v-progress-circular indeterminate color="primary" size="64" />
|
||||
</div>
|
||||
|
||||
<div v-else-if="loadError" class="loading-container">
|
||||
<v-icon size="72" color="error">mdi-alert-circle-outline</v-icon>
|
||||
<p class="mt-4 text-medium-emphasis">{{ t('states.loadError') }}</p>
|
||||
<v-btn class="mt-4" prepend-icon="mdi-refresh" color="primary" variant="tonal" @click="loadKB">
|
||||
{{ t('states.retry') }}
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
<!-- 主内容 -->
|
||||
<div v-else class="kb-content">
|
||||
<!-- 标签页 -->
|
||||
@@ -173,6 +181,7 @@ const emit = defineEmits<{
|
||||
|
||||
const kbId = ref(route.params.kbId as string)
|
||||
const loading = ref(true)
|
||||
const loadError = ref(false)
|
||||
const activeTab = ref('overview')
|
||||
const kb = ref<any>({})
|
||||
|
||||
@@ -191,17 +200,21 @@ const showSnackbar = (text: string, color: string = 'success') => {
|
||||
// 加载知识库详情
|
||||
const loadKB = async () => {
|
||||
loading.value = true
|
||||
loadError.value = false
|
||||
try {
|
||||
const response = await knowledgeApi.get(kbId.value)
|
||||
if (response.data.status === 'ok') {
|
||||
kb.value = response.data.data
|
||||
loadError.value = false
|
||||
emit('title-change', kb.value.kb_name || '')
|
||||
} else {
|
||||
showSnackbar(response.data.message || '加载失败', 'error')
|
||||
loadError.value = true
|
||||
showSnackbar(response.data.message || t('states.loadError'), 'error')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load knowledge base:', error)
|
||||
showSnackbar('加载知识库详情失败', 'error')
|
||||
loadError.value = true
|
||||
showSnackbar(t('states.loadError'), 'error')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
@@ -5,6 +5,15 @@
|
||||
<p class="mt-4 text-medium-emphasis">{{ t('list.loading') }}</p>
|
||||
</div>
|
||||
|
||||
<div v-else-if="loadError && kbList.length === 0" class="empty-state">
|
||||
<v-icon size="72" color="error">mdi-alert-circle-outline</v-icon>
|
||||
<h2 class="mt-4">{{ t('messages.loadError') }}</h2>
|
||||
<v-btn class="mt-6" prepend-icon="mdi-refresh" color="primary" variant="tonal"
|
||||
@click="loadKnowledgeBases()">
|
||||
{{ t('list.retry') }}
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
<div v-else-if="kbList.length > 0" class="kb-list">
|
||||
<OutlinedActionListItem
|
||||
v-for="kb in kbList"
|
||||
@@ -277,6 +286,7 @@ const router = useRouter()
|
||||
|
||||
// 状态
|
||||
const loading = ref(false)
|
||||
const loadError = ref(false)
|
||||
const saving = ref(false)
|
||||
const deleting = ref(false)
|
||||
const kbList = ref<any[]>([])
|
||||
@@ -337,6 +347,7 @@ const emojiCategories = [
|
||||
// 加载知识库列表
|
||||
const loadKnowledgeBases = async (refreshStats = false) => {
|
||||
loading.value = true
|
||||
loadError.value = false
|
||||
try {
|
||||
if (refreshStats) {
|
||||
page.value = 1
|
||||
@@ -350,11 +361,14 @@ const loadKnowledgeBases = async (refreshStats = false) => {
|
||||
const data = response.data.data
|
||||
kbList.value = data.items || []
|
||||
total.value = data.total || 0
|
||||
loadError.value = false
|
||||
} else {
|
||||
loadError.value = true
|
||||
showSnackbar(response.data.message || t('messages.loadError'), 'error')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load knowledge bases:', error)
|
||||
loadError.value = true
|
||||
showSnackbar(t('messages.loadError'), 'error')
|
||||
} finally {
|
||||
loading.value = false
|
||||
|
||||
Reference in New Issue
Block a user