feat(knowledge): add batch synchronization
This commit is contained in:
@@ -8,6 +8,7 @@ import TableRowActions from "./TableRowActions.vue";
|
||||
import AdminPagination from "./AdminPagination.vue";
|
||||
import type {
|
||||
KnowledgeDetail,
|
||||
KnowledgeBatchSyncResult,
|
||||
KnowledgeItem,
|
||||
KnowledgeSyncJob,
|
||||
MigrationSummary,
|
||||
@@ -29,6 +30,9 @@ const editOpen = ref(false);
|
||||
const editSaving = ref(false);
|
||||
const batchOpen = ref(false);
|
||||
const batchSaving = ref(false);
|
||||
const batchSyncing = ref(false);
|
||||
const batchSyncResultOpen = ref(false);
|
||||
const batchSyncResult = ref<KnowledgeBatchSyncResult | null>(null);
|
||||
const resolvingNode = ref(false);
|
||||
const nodeResolved = ref(false);
|
||||
const sourceTitle = ref("");
|
||||
@@ -130,6 +134,32 @@ async function saveBatchMetadata() {
|
||||
}
|
||||
}
|
||||
|
||||
async function syncSelected() {
|
||||
if (!selectedRows.value.length) {
|
||||
ElMessage.warning("请先勾选需要同步的知识库");
|
||||
return;
|
||||
}
|
||||
if (!await confirmAction(
|
||||
`将依次同步已选择的 ${selectedRows.value.length} 个知识库。同步成功后最新内容立即生效,单个失败不会中断其他知识库。`,
|
||||
"确认批量同步",
|
||||
{ confirmButtonText: "开始同步", cancelButtonText: "取消", type: "warning" },
|
||||
)) return;
|
||||
batchSyncing.value = true;
|
||||
try {
|
||||
const result = await api.batchSyncKnowledge(selectedRows.value.map((item) => item.id));
|
||||
batchSyncResult.value = result;
|
||||
batchSyncResultOpen.value = true;
|
||||
ElMessage[result.failed ? "warning" : "success"](
|
||||
`批量同步完成:成功 ${result.success} 个,失败 ${result.failed} 个`,
|
||||
);
|
||||
await load();
|
||||
} catch (error) {
|
||||
ElMessage.error(errorMessage(error, "批量同步失败"));
|
||||
} finally {
|
||||
batchSyncing.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function handleMore(command: string, item: KnowledgeItem) {
|
||||
try {
|
||||
if (command === "detail") return await openDetail(item);
|
||||
@@ -353,7 +383,10 @@ async function confirmAction(
|
||||
|
||||
<div class="knowledge-batch-bar">
|
||||
<span>已选择 {{ selectedRows.length }} 个知识库</span>
|
||||
<el-button :disabled="selectedRows.length === 0" @click="openBatchEdit">批量修改类型</el-button>
|
||||
<div class="knowledge-batch-actions">
|
||||
<el-button type="primary" plain :disabled="selectedRows.length === 0 || batchSaving" :loading="batchSyncing" @click="syncSelected">批量同步</el-button>
|
||||
<el-button :disabled="selectedRows.length === 0 || batchSyncing" @click="openBatchEdit">批量修改类型</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-table v-loading="loading" :data="rows" stripe @selection-change="selectedRows = $event">
|
||||
@@ -404,6 +437,28 @@ async function confirmAction(
|
||||
</el-form>
|
||||
<template #footer><el-button @click="batchOpen = false">取消</el-button><el-button type="primary" :loading="batchSaving" @click="saveBatchMetadata">下一步</el-button></template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="batchSyncResultOpen" title="批量同步结果" width="min(760px, 94vw)" append-to-body destroy-on-close>
|
||||
<el-alert
|
||||
v-if="batchSyncResult"
|
||||
:title="`共处理 ${batchSyncResult.total} 个:成功 ${batchSyncResult.success} 个,失败 ${batchSyncResult.failed} 个`"
|
||||
:type="batchSyncResult.failed ? 'warning' : 'success'"
|
||||
:closable="false"
|
||||
show-icon
|
||||
/>
|
||||
<el-table v-if="batchSyncResult" :data="batchSyncResult.results" max-height="440" class="batch-sync-result-table">
|
||||
<el-table-column label="知识库" min-width="220">
|
||||
<template #default="{ row }">{{ row.name || `知识库 #${row.knowledgeId}` }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="结果" width="100">
|
||||
<template #default="{ row }"><el-tag :type="row.ok ? 'success' : 'danger'">{{ row.ok ? '成功' : '失败' }}</el-tag></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态 / 原因" min-width="300">
|
||||
<template #default="{ row }">{{ row.ok ? (row.status === 'unchanged' ? '内容无变化' : '最新内容已生效') : row.error }}</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template #footer><el-button type="primary" @click="batchSyncResultOpen = false">完成</el-button></template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@@ -421,6 +476,12 @@ async function confirmAction(
|
||||
color: #66756f;
|
||||
}
|
||||
|
||||
.knowledge-batch-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.knowledge-section-head h4 {
|
||||
margin: 0;
|
||||
}
|
||||
@@ -440,4 +501,8 @@ async function confirmAction(
|
||||
.batch-edit-form {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.batch-sync-result-table {
|
||||
margin-top: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -15,6 +15,7 @@ import type {
|
||||
KnowledgeSyncJob,
|
||||
KnowledgeVersionContent,
|
||||
MigrationSummary,
|
||||
KnowledgeBatchSyncResult,
|
||||
KnowledgeBatchUpdateResult,
|
||||
RetrievalLogItem,
|
||||
AttentionItem,
|
||||
@@ -142,6 +143,11 @@ export const api = {
|
||||
request<KnowledgeItem>(`/admin/knowledge/${id}/metadata`, { method: "PATCH", body: JSON.stringify(payload) }),
|
||||
batchUpdateKnowledgeMetadata: (payload: { knowledgeIds: number[]; knowledgeType?: string }) =>
|
||||
request<KnowledgeBatchUpdateResult>("/admin/knowledge/batch/metadata", { method: "PATCH", body: JSON.stringify(payload) }),
|
||||
batchSyncKnowledge: (knowledgeIds: number[]) =>
|
||||
request<KnowledgeBatchSyncResult>("/admin/knowledge/batch/sync", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ knowledgeIds }),
|
||||
}),
|
||||
deleteKnowledge: (id: number) => request<null>(`/admin/knowledge/${id}`, { method: "DELETE" }),
|
||||
importKnowledgeFromSpace: (body: { node_token: string }) =>
|
||||
request<{ imported: number; skipped: number; id: number; name: string }>(
|
||||
|
||||
@@ -222,6 +222,20 @@ export interface KnowledgeBatchUpdateResult {
|
||||
results: Array<{ knowledgeId: number; ok: boolean; error?: string }>;
|
||||
}
|
||||
|
||||
export interface KnowledgeBatchSyncResult {
|
||||
total: number;
|
||||
success: number;
|
||||
failed: number;
|
||||
results: Array<{
|
||||
knowledgeId: number;
|
||||
name?: string;
|
||||
ok: boolean;
|
||||
status?: string;
|
||||
job?: KnowledgeSyncJob;
|
||||
error?: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export interface RetrievalLogItem {
|
||||
id: number;
|
||||
sessionId?: number | null;
|
||||
|
||||
Reference in New Issue
Block a user