mirror of
https://github.com/ccmjga/zhilu-admin
synced 2026-04-11 08:47:21 +00:00
新增知识库相关组件,包括文档卡片、知识库卡片、状态徽章和分段卡片,优化日期格式化工具函数,更新文档管理和知识库管理页面以使用新组件。
This commit is contained in:
@@ -0,0 +1,36 @@
|
|||||||
|
<template>
|
||||||
|
<div class="bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md transition-shadow">
|
||||||
|
<div class="p-4">
|
||||||
|
<div class="flex justify-between items-start">
|
||||||
|
<div>
|
||||||
|
<h5 class="text-xl font-semibold tracking-tight text-gray-900 mb-1 truncate">{{ doc.name }}</h5>
|
||||||
|
<div class="flex items-center mb-2">
|
||||||
|
<KnowledgeStatusBadge :status="doc.status" type="status" class="mr-2" />
|
||||||
|
<KnowledgeStatusBadge :enabled="doc.enable" type="enabled" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex space-x-2">
|
||||||
|
<slot name="toggle-switch"></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<span class="text-xs text-gray-500">
|
||||||
|
上传时间: {{ formatDateString(doc.createTime) }}
|
||||||
|
</span>
|
||||||
|
<div class="flex space-x-2">
|
||||||
|
<slot name="actions"></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { KnowledgeStatusBadge } from '@/components/common/knowledge';
|
||||||
|
import type { LibraryDoc } from "@/types/KnowledgeTypes";
|
||||||
|
import { formatDateString } from '@/utils/dateUtil';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
doc: LibraryDoc;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<template>
|
||||||
|
<div class="bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md transition-shadow">
|
||||||
|
<div class="p-4">
|
||||||
|
<div class="flex justify-between items-start">
|
||||||
|
<h5 class="text-xl font-semibold tracking-tight text-gray-900 mb-1 truncate">{{ library.name }}</h5>
|
||||||
|
<div class="flex space-x-2">
|
||||||
|
<slot name="actions-top"></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="text-sm text-gray-600 mb-3 line-clamp-2">
|
||||||
|
{{ library.description || '暂无描述' }}
|
||||||
|
</p>
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<span class="text-xs text-gray-500">
|
||||||
|
创建时间: {{ formatDateString(library.createTime) }}
|
||||||
|
</span>
|
||||||
|
<slot name="actions-bottom"></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { Library } from "@/types/KnowledgeTypes";
|
||||||
|
import { formatDateString } from '@/utils/dateUtil';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
library: Library;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<template>
|
||||||
|
<span :class="`inline-flex items-center px-2 py-1 text-xs font-medium rounded-full ${
|
||||||
|
getStatusClass()
|
||||||
|
}`">
|
||||||
|
{{ getStatusText() }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { DocStatus } from "@/types/KnowledgeTypes";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
status?: string;
|
||||||
|
enabled?: boolean;
|
||||||
|
type: 'status' | 'enabled';
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const getStatusClass = () => {
|
||||||
|
if (props.type === 'status') {
|
||||||
|
return props.status === DocStatus.SUCCESS
|
||||||
|
? 'bg-green-100 text-green-800'
|
||||||
|
: 'bg-yellow-100 text-yellow-800';
|
||||||
|
}
|
||||||
|
|
||||||
|
return props.enabled
|
||||||
|
? 'bg-blue-100 text-blue-800'
|
||||||
|
: 'bg-gray-100 text-gray-800';
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStatusText = () => {
|
||||||
|
if (props.type === 'status') {
|
||||||
|
return props.status === DocStatus.SUCCESS ? '解析完成' : '解析中';
|
||||||
|
}
|
||||||
|
|
||||||
|
return props.enabled ? '已启用' : '已禁用';
|
||||||
|
};
|
||||||
|
</script>
|
||||||
34
frontend/src/components/common/knowledge/SegmentCard.vue
Normal file
34
frontend/src/components/common/knowledge/SegmentCard.vue
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<template>
|
||||||
|
<div class="bg-white border border-gray-200 rounded-lg shadow-sm p-4">
|
||||||
|
<div class="flex justify-between items-start mb-2">
|
||||||
|
<h5 class="text-lg font-semibold text-gray-900">分段 #{{ index + 1 }}</h5>
|
||||||
|
<div class="text-xs text-gray-500">
|
||||||
|
ID: {{ segment.id }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-sm text-gray-500 mb-2">
|
||||||
|
<div class="flex flex-wrap gap-2">
|
||||||
|
<span class="inline-flex items-center px-2 py-1 text-xs font-medium rounded-full bg-blue-100 text-blue-800">
|
||||||
|
Embedding ID: {{ segment.embeddingId || '无' }}
|
||||||
|
</span>
|
||||||
|
<span class="inline-flex items-center px-2 py-1 text-xs font-medium rounded-full bg-green-100 text-green-800">
|
||||||
|
Token 使用量: {{ segment.tokenUsage || 0 }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="border-t border-gray-200 pt-3 mt-3">
|
||||||
|
<h6 class="text-sm font-medium text-gray-900 mb-2">内容:</h6>
|
||||||
|
<pre
|
||||||
|
class="text-sm text-gray-700 whitespace-pre-wrap bg-gray-50 p-3 rounded-lg max-h-60 overflow-y-auto">{{ segment.content }}</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { LibraryDocSegment } from "@/types/KnowledgeTypes";
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
segment: LibraryDocSegment;
|
||||||
|
index: number;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
11
frontend/src/components/common/knowledge/index.ts
Normal file
11
frontend/src/components/common/knowledge/index.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import KnowledgeDocCard from "./KnowledgeDocCard.vue";
|
||||||
|
import KnowledgeLibraryCard from "./KnowledgeLibraryCard.vue";
|
||||||
|
import KnowledgeStatusBadge from "./KnowledgeStatusBadge.vue";
|
||||||
|
import SegmentCard from "./SegmentCard.vue";
|
||||||
|
|
||||||
|
export {
|
||||||
|
KnowledgeStatusBadge,
|
||||||
|
KnowledgeDocCard,
|
||||||
|
KnowledgeLibraryCard,
|
||||||
|
SegmentCard,
|
||||||
|
};
|
||||||
@@ -13,4 +13,9 @@ const formatDate = (date?: Date) => {
|
|||||||
return dayjs(date).format("YYYY-MM-DDTHH:mm:ss.SSSZ");
|
return dayjs(date).format("YYYY-MM-DDTHH:mm:ss.SSSZ");
|
||||||
};
|
};
|
||||||
|
|
||||||
export { dayjs, formatDate };
|
const formatDateString = (dateString?: string, format = "YYYY-MM-DD HH:mm") => {
|
||||||
|
if (!dateString) return "未知";
|
||||||
|
return dayjs(dateString).format(format);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { dayjs, formatDate, formatDateString };
|
||||||
|
|||||||
@@ -5,63 +5,36 @@
|
|||||||
<h1 class="text-xl font-semibold text-gray-900 sm:text-2xl">{{ currentLibrary?.name || '知识库' }} - 文档管理</h1>
|
<h1 class="text-xl font-semibold text-gray-900 sm:text-2xl">{{ currentLibrary?.name || '知识库' }} - 文档管理</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
<!-- 文档列表 -->
|
||||||
<div v-for="doc in docs" :key="doc.id"
|
<div v-if="docs.length > 0" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
class="bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md transition-shadow">
|
<KnowledgeDocCard v-for="doc in docs" :key="doc.id" :doc="doc">
|
||||||
<div class="p-4">
|
<template #toggle-switch>
|
||||||
<div class="flex justify-between items-start">
|
<label class="inline-flex items-center mb-5"
|
||||||
<div>
|
:class="!doc.enable ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'">
|
||||||
<h5 class="text-xl font-semibold tracking-tight text-gray-900 mb-1 truncate">{{ doc.name }}</h5>
|
<input type="checkbox" class="sr-only peer" :checked="doc.enable" @change="handleToggleDocStatus(doc)">
|
||||||
<div class="flex items-center mb-2">
|
<div
|
||||||
<span :class="`inline-flex items-center px-2 py-1 text-xs font-medium rounded-full ${
|
class="relative w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:w-5 after:h-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600">
|
||||||
doc.status === DocStatus.SUCCESS ? 'bg-green-100 text-green-800' : 'bg-yellow-100 text-yellow-800'
|
|
||||||
} mr-2`">
|
|
||||||
{{ doc.status === DocStatus.SUCCESS ? '解析完成' : '解析中' }}
|
|
||||||
</span>
|
|
||||||
<span :class="`inline-flex items-center px-2 py-1 text-xs font-medium rounded-full ${
|
|
||||||
doc.enable ? 'bg-blue-100 text-blue-800' : 'bg-gray-100 text-gray-800'
|
|
||||||
}`">
|
|
||||||
{{ doc.enable ? '已启用' : '已禁用' }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex space-x-2">
|
</label>
|
||||||
<label class="inline-flex items-center mb-5"
|
</template>
|
||||||
:class="!doc.enable ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'">
|
<template #actions>
|
||||||
<input type="checkbox" class="sr-only peer" :checked="doc.enable" @change="handleToggleDocStatus(doc)">
|
<button @click="navigateToDocSegments(doc)" :class="
|
||||||
<div
|
['text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-xs px-3 py-content',
|
||||||
class="relative w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300 rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:w-5 after:h-5 after:transition-all dark:border-gray-600 peer-checked:bg-blue-600">
|
doc.status !== DocStatus.SUCCESS ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer']"
|
||||||
</div>
|
:disabled="doc.status !== DocStatus.SUCCESS">
|
||||||
</label>
|
查看内容
|
||||||
|
</button>
|
||||||
</div>
|
<button @click="handleDeleteDoc(doc)"
|
||||||
</div>
|
class="text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:ring-red-300 font-medium rounded-lg text-xs px-3 py-1.5">
|
||||||
<!-- <div class="text-sm text-gray-600 mb-3">
|
删除
|
||||||
<div class="truncate">{{ doc.path || '无' }}</div>
|
</button>
|
||||||
</div> -->
|
</template>
|
||||||
<div class="flex justify-between items-center">
|
</KnowledgeDocCard>
|
||||||
<span class="text-xs text-gray-500">
|
|
||||||
上传时间: {{ formatDate(doc.createTime) }}
|
|
||||||
</span>
|
|
||||||
<div class="flex space-x-2">
|
|
||||||
<button @click="navigateToDocSegments(doc)" :class="
|
|
||||||
['text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-xs px-3 py-content',
|
|
||||||
doc.status !== DocStatus.SUCCESS ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer']"
|
|
||||||
:disabled="doc.status !== DocStatus.SUCCESS">
|
|
||||||
查看内容
|
|
||||||
</button>
|
|
||||||
<button @click="handleDeleteDoc(doc)"
|
|
||||||
class="text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:ring-red-300 font-medium rounded-lg text-xs px-3 py-1.5">
|
|
||||||
删除
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col items-center justify-center py-10">
|
|
||||||
<div v-if="docs.length === 0" class="text-gray-500 text-lg mb-4">暂无文档</div>
|
<!-- 空状态 -->
|
||||||
|
<div v-else class="flex flex-col items-center justify-center py-10">
|
||||||
|
<div class="text-gray-500 text-lg mb-4">暂无文档</div>
|
||||||
<div>
|
<div>
|
||||||
<input ref="fileInputRef" class="hidden" id="doc_file_input" type="file" @change="handleFileChange">
|
<input ref="fileInputRef" class="hidden" id="doc_file_input" type="file" @change="handleFileChange">
|
||||||
<TableButton variant="primary" size="md" @click="triggerFileInput">
|
<TableButton variant="primary" size="md" @click="triggerFileInput">
|
||||||
@@ -84,11 +57,11 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import dayjs from "dayjs";
|
|
||||||
import { Modal, type ModalInterface, initFlowbite } from "flowbite";
|
import { Modal, type ModalInterface, initFlowbite } from "flowbite";
|
||||||
import { onMounted, ref, watchEffect } from "vue";
|
import { onMounted, ref, watchEffect } from "vue";
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
|
||||||
|
import { KnowledgeDocCard, KnowledgeStatusBadge } from "@/components/common/knowledge";
|
||||||
import { PlusIcon } from "@/components/icons";
|
import { PlusIcon } from "@/components/icons";
|
||||||
import Breadcrumbs from "@/components/layout/Breadcrumbs.vue";
|
import Breadcrumbs from "@/components/layout/Breadcrumbs.vue";
|
||||||
import ConfirmationDialog from "@/components/modals/ConfirmationDialog.vue";
|
import ConfirmationDialog from "@/components/modals/ConfirmationDialog.vue";
|
||||||
@@ -98,6 +71,7 @@ import { useKnowledgeQuery } from "@/composables/knowledge/useKnowledgeQuery";
|
|||||||
import { useKnowledgeUpsert } from "@/composables/knowledge/useKnowledgeUpsert";
|
import { useKnowledgeUpsert } from "@/composables/knowledge/useKnowledgeUpsert";
|
||||||
import useAlertStore from "@/composables/store/useAlertStore";
|
import useAlertStore from "@/composables/store/useAlertStore";
|
||||||
import { Routes } from "@/router/constants";
|
import { Routes } from "@/router/constants";
|
||||||
|
import { formatDateString } from '@/utils/dateUtil';
|
||||||
|
|
||||||
import type { Library, LibraryDoc } from "@/types/KnowledgeTypes";
|
import type { Library, LibraryDoc } from "@/types/KnowledgeTypes";
|
||||||
import { DocStatus } from "@/types/KnowledgeTypes";
|
import { DocStatus } from "@/types/KnowledgeTypes";
|
||||||
@@ -129,12 +103,6 @@ const selectedDoc = ref<LibraryDoc | undefined>();
|
|||||||
// 提示store
|
// 提示store
|
||||||
const alertStore = useAlertStore();
|
const alertStore = useAlertStore();
|
||||||
|
|
||||||
// 格式化日期
|
|
||||||
const formatDate = (dateString?: string) => {
|
|
||||||
if (!dateString) return "未知";
|
|
||||||
return dayjs(dateString).format("YYYY-MM-DD HH:mm");
|
|
||||||
};
|
|
||||||
|
|
||||||
// 触发文件选择
|
// 触发文件选择
|
||||||
const triggerFileInput = () => {
|
const triggerFileInput = () => {
|
||||||
fileInputRef.value?.click();
|
fileInputRef.value?.click();
|
||||||
|
|||||||
@@ -5,48 +5,38 @@
|
|||||||
<h1 class="text-2xl font-semibold text-gray-900">知识库管理</h1>
|
<h1 class="text-2xl font-semibold text-gray-900">知识库管理</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
<!-- 知识库列表 -->
|
||||||
<div v-for="library in libraries" :key="library.id"
|
<div v-if="libraries.length > 0" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
class="bg-white border border-gray-200 rounded-lg shadow-sm hover:shadow-md transition-shadow">
|
<KnowledgeLibraryCard v-for="library in libraries" :key="library.id" :library="library">
|
||||||
<div class="p-4">
|
<template #actions-top>
|
||||||
<div class="flex justify-between items-start">
|
<button @click="handleEditLibrary(library)" class="text-gray-500 hover:text-blue-700 focus:outline-none">
|
||||||
<h5 class="text-xl font-semibold tracking-tight text-gray-900 mb-1 truncate">{{ library.name }}</h5>
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"
|
||||||
<div class="flex space-x-2">
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
<button @click="handleEditLibrary(library)" class="text-gray-500 hover:text-blue-700 focus:outline-none">
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"
|
d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z">
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
</path>
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
</svg>
|
||||||
d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z">
|
</button>
|
||||||
</path>
|
<button @click="handleDeleteLibrary(library)" class="text-gray-500 hover:text-red-700 focus:outline-none">
|
||||||
</svg>
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"
|
||||||
</button>
|
xmlns="http://www.w3.org/2000/svg">
|
||||||
<button @click="handleDeleteLibrary(library)" class="text-gray-500 hover:text-red-700 focus:outline-none">
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"
|
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16">
|
||||||
xmlns="http://www.w3.org/2000/svg">
|
</path>
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
</svg>
|
||||||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16">
|
</button>
|
||||||
</path>
|
</template>
|
||||||
</svg>
|
<template #actions-bottom>
|
||||||
</button>
|
<button @click="navigateToLibraryDocs(library)"
|
||||||
</div>
|
class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-xs px-3 py-1.5">
|
||||||
</div>
|
查看知识库
|
||||||
<p class="text-sm text-gray-600 mb-3 line-clamp-2">
|
</button>
|
||||||
{{ library.description || '暂无描述' }}
|
</template>
|
||||||
</p>
|
</KnowledgeLibraryCard>
|
||||||
<div class="flex justify-between items-center">
|
|
||||||
<span class="text-xs text-gray-500">
|
|
||||||
创建时间: {{ formatDate(library.createTime) }}
|
|
||||||
</span>
|
|
||||||
<button @click="navigateToLibraryDocs(library)"
|
|
||||||
class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-xs px-3 py-1.5">
|
|
||||||
查看知识库
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="libraries.length === 0" class="flex flex-col items-center justify-center py-10">
|
<!-- 空状态 -->
|
||||||
|
<div v-else class="flex flex-col items-center justify-center py-10">
|
||||||
<div class="text-gray-500 text-lg mb-4">暂无知识库</div>
|
<div class="text-gray-500 text-lg mb-4">暂无知识库</div>
|
||||||
<div>
|
<div>
|
||||||
<button @click="handleCreateLibraryClick"
|
<button @click="handleCreateLibraryClick"
|
||||||
@@ -75,6 +65,7 @@ import { Modal, type ModalInterface, initFlowbite } from "flowbite";
|
|||||||
import { onMounted, ref } from "vue";
|
import { onMounted, ref } from "vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
|
|
||||||
|
import { KnowledgeLibraryCard } from "@/components/common/knowledge";
|
||||||
import Breadcrumbs from "@/components/layout/Breadcrumbs.vue";
|
import Breadcrumbs from "@/components/layout/Breadcrumbs.vue";
|
||||||
import ConfirmationDialog from "@/components/modals/ConfirmationDialog.vue";
|
import ConfirmationDialog from "@/components/modals/ConfirmationDialog.vue";
|
||||||
import LibraryFormDialog from "@/components/modals/LibraryFormDialog.vue";
|
import LibraryFormDialog from "@/components/modals/LibraryFormDialog.vue";
|
||||||
|
|||||||
@@ -9,36 +9,14 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 分段列表 -->
|
<!-- 空状态 -->
|
||||||
<div v-if="segments.length === 0" class="flex flex-col items-center justify-center py-10">
|
<div v-if="segments.length === 0" class="flex flex-col items-center justify-center py-10">
|
||||||
<div class="text-gray-500 text-lg">暂无分段内容</div>
|
<div class="text-gray-500 text-lg">暂无分段内容</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 分段列表 -->
|
||||||
<div v-else class="space-y-4">
|
<div v-else class="space-y-4">
|
||||||
<div v-for="(segment, index) in segments" :key="segment.id"
|
<SegmentCard v-for="(segment, index) in segments" :key="segment.id" :segment="segment" :index="index" />
|
||||||
class="bg-white border border-gray-200 rounded-lg shadow-sm p-4">
|
|
||||||
<div class="flex justify-between items-start mb-2">
|
|
||||||
<h5 class="text-lg font-semibold text-gray-900">分段 #{{ index + 1 }}</h5>
|
|
||||||
<div class="text-xs text-gray-500">
|
|
||||||
ID: {{ segment.id }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="text-sm text-gray-500 mb-2">
|
|
||||||
<div class="flex flex-wrap gap-2">
|
|
||||||
<span class="inline-flex items-center px-2 py-1 text-xs font-medium rounded-full bg-blue-100 text-blue-800">
|
|
||||||
Embedding ID: {{ segment.embeddingId || '无' }}
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
class="inline-flex items-center px-2 py-1 text-xs font-medium rounded-full bg-green-100 text-green-800">
|
|
||||||
Token 使用量: {{ segment.tokenUsage || 0 }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="border-t border-gray-200 pt-3 mt-3">
|
|
||||||
<h6 class="text-sm font-medium text-gray-900 mb-2">内容:</h6>
|
|
||||||
<pre
|
|
||||||
class="text-sm text-gray-700 whitespace-pre-wrap bg-gray-50 p-3 rounded-lg max-h-60 overflow-y-auto">{{ segment.content }}</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -47,6 +25,7 @@
|
|||||||
import { onMounted, ref, watchEffect } from "vue";
|
import { onMounted, ref, watchEffect } from "vue";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
|
|
||||||
|
import { SegmentCard } from "@/components/common/knowledge";
|
||||||
import Breadcrumbs from "@/components/layout/Breadcrumbs.vue";
|
import Breadcrumbs from "@/components/layout/Breadcrumbs.vue";
|
||||||
import { useKnowledgeQuery } from "@/composables/knowledge/useKnowledgeQuery";
|
import { useKnowledgeQuery } from "@/composables/knowledge/useKnowledgeQuery";
|
||||||
import { Routes } from "@/router/constants";
|
import { Routes } from "@/router/constants";
|
||||||
|
|||||||
Reference in New Issue
Block a user