diff --git a/ai_knowledge_base_v2/apps/admin-web/src/components/KnowledgeContentPreview.vue b/ai_knowledge_base_v2/apps/admin-web/src/components/KnowledgeContentPreview.vue index 637e039..ba05082 100644 --- a/ai_knowledge_base_v2/apps/admin-web/src/components/KnowledgeContentPreview.vue +++ b/ai_knowledge_base_v2/apps/admin-web/src/components/KnowledgeContentPreview.vue @@ -6,6 +6,8 @@ import type { KnowledgeVersionContent } from "../types/api"; const props = defineProps<{ versionId: number | null; + targetSectionId?: number | null; + highlightKeyword?: string; }>(); const loading = ref(false); @@ -25,6 +27,7 @@ const characterCount = computed(() => ( )); watch(() => props.versionId, loadVersion, { immediate: true }); +watch(() => props.targetSectionId, selectTargetSection); async function loadVersion(versionId: number | null) { const sequence = ++requestSequence; @@ -38,7 +41,9 @@ async function loadVersion(versionId: number | null) { const result = await api.knowledgeVersionContent(versionId); if (sequence !== requestSequence) return; content.value = result; - activeSectionId.value = result.sections[0]?.id ?? null; + activeSectionId.value = props.targetSectionId && result.sections.some((section) => section.id === props.targetSectionId) + ? props.targetSectionId + : result.sections[0]?.id ?? null; } catch (loadError) { if (sequence !== requestSequence) return; error.value = loadError instanceof Error ? loadError.message : "知识库内容加载失败"; @@ -47,6 +52,32 @@ async function loadVersion(versionId: number | null) { } } +function selectTargetSection(sectionId?: number | null) { + if (!sectionId || !content.value?.sections.some((section) => section.id === sectionId)) return; + activeSectionId.value = sectionId; +} + +function highlightedParts(text: string) { + const keyword = (props.highlightKeyword || "").trim(); + if (!keyword) return [{ text, match: false }]; + const parts: Array<{ text: string; match: boolean }> = []; + const source = text || ""; + const lowerSource = source.toLowerCase(); + const lowerKeyword = keyword.toLowerCase(); + let cursor = 0; + while (cursor < source.length) { + const index = lowerSource.indexOf(lowerKeyword, cursor); + if (index < 0) { + parts.push({ text: source.slice(cursor), match: false }); + break; + } + if (index > cursor) parts.push({ text: source.slice(cursor, index), match: false }); + parts.push({ text: source.slice(index, index + keyword.length), match: true }); + cursor = index + keyword.length; + } + return parts.length ? parts : [{ text: source, match: false }]; +} +