Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ui/src/api/API_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ PUT `/<id>/document/batch_generate_related`,单项也传 document_id_list,

getKnowledgeMcpConfig 查询 external_service 并格式化 mcp_config;putKnowledgeKeywordIndex PUT tokenize 提交索引。
exportKnowledgeExcel、exportKnowledgeZip、exportKnowledge 下载文档 Excel、带图片文档 ZIP、可导入知识库 ZIP;
exportKnowledge 第三个参数为 withSourceFile,通过查询参数 with_source_file 传入是否包含源文件。
postKnowledgeImport 以 FormData file、folder_id 上传,响应 knowledge_id、type。

putKnowledge 更新通用字段,Workspace 飞书使用 putLarkKnowledge;移动传 folder_id,批量移动/删除传 id_list。
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ const exportKnowledgeZip = (knowledgeId: string, knowledgeName: string) => {
}

/** 导出可用于导入创建的知识库压缩包。 */
const exportKnowledge = (knowledgeId: string, knowledgeName: string) => {
return getExportFile(`${knowledgeName}.zip`, `${prefix}/${knowledgeId}/export_knowledge`)
const exportKnowledge = (knowledgeId: string, knowledgeName: string, withSourceFile: boolean) => {
return getExportFile(`${knowledgeName}.zip`, `${prefix}/${knowledgeId}/export_knowledge`, { with_source_file: withSourceFile })
}

/** 获取知识库外部检索服务生成的 MCP 连接配置。 */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ const exportKnowledgeZip = (knowledgeId: string, knowledgeName: string) =>
getExportFile(`${knowledgeName}.zip`, `${prefix}/${knowledgeId}/export_zip`)

/** 导出可用于导入创建的知识库压缩包。 */
const exportKnowledge = (knowledgeId: string, knowledgeName: string) =>
getExportFile(`${knowledgeName}.zip`, `${prefix}/${knowledgeId}/export_knowledge`)
const exportKnowledge = (knowledgeId: string, knowledgeName: string, withSourceFile: boolean) =>
getExportFile(`${knowledgeName}.zip`, `${prefix}/${knowledgeId}/export_knowledge`, { with_source_file: withSourceFile })

/** 获取知识库外部检索服务生成的 MCP 连接配置。 */
const getKnowledgeMcpConfig = (knowledgeId: string): Promise<string> =>
Expand Down
4 changes: 2 additions & 2 deletions ui/src/api/admin/workspace/knowledge/knowledge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ const exportKnowledgeZip = (knowledgeId: string, knowledgeName: string) => {
}

/** 导出可用于导入创建的知识库压缩包。 */
const exportKnowledge = (knowledgeId: string, knowledgeName: string) => {
return getExportFile(`${knowledgeName}.zip`, `${getPrefix()}/${knowledgeId}/export_knowledge`)
const exportKnowledge = (knowledgeId: string, knowledgeName: string, withSourceFile: boolean) => {
return getExportFile(`${knowledgeName}.zip`, `${getPrefix()}/${knowledgeId}/export_knowledge`, { with_source_file: withSourceFile })
}

/** 导入知识库文件并在指定文件夹创建知识库。 */
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/COMPONENT_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -833,7 +833,7 @@ Workspace 的文件夹虚拟树业务组件。组件根据当前资源上下文
`(Partial<KnowledgeItem> & { id: string })[]`,保留必需的 ID 并兼容缺少详情的旧数据,
组件采用 `MkViewLayout` 左右布局,搜索栏位于内容区右上角,刷新位于弹窗标题栏。
选项使用紧凑三列布局(窄屏减少列数),左侧图标与省略名称、右侧复选框。点击卡片或复选框
切换选择,选中后仅展示相同 Embedding 模型的选项,清空后恢复;悬停展示知识库详情。
切换选择,始终过滤掉 `embedding_model_id` 为空的知识库;选中后仅展示相同 Embedding 模型的选项,清空后恢复可选范围;悬停展示知识库详情。
按工作空间、System 资源管理、System 共享资源选择完整 Knowledge API 的 `getAllKnowledge`,
一次加载当前查询的全部知识库,不使用滚动分页,不增加 Workspace 共享页面来源分支。
仅普通工作空间显示只读 `FolderTree`,不显示共享目录、不调用 Workspace Shared API;其他范围不显示或查询文件夹。
Expand Down
6 changes: 3 additions & 3 deletions ui/src/components/business/select-knowledge-dialog/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ const isWorkspaceScope = computed(() => isWorkspaceResource())
const selectedKnowledgeIds = computed(() => selectedKnowledge.value.map(({ id }) => id))
const embeddingModelId = computed(() => selectedKnowledge.value.find((knowledge) => knowledge.embedding_model_id)?.embedding_model_id)
const filteredKnowledge = computed(() =>
embeddingModelId.value
? knowledgeOptions.value.filter((knowledge) => knowledge.embedding_model_id === embeddingModelId.value)
: knowledgeOptions.value,
knowledgeOptions.value.filter(
(knowledge) => knowledge.embedding_model_id && (!embeddingModelId.value || knowledge.embedding_model_id === embeddingModelId.value),
),
)

function toggleKnowledge(knowledge: KnowledgeItem) {
Expand Down
3 changes: 2 additions & 1 deletion ui/src/components/mk-echart/LineCharts.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ const chartOption = computed<LineOption>(() => ({
itemHeight: 8,
textStyle: { color: '#646A73' },
},
grid: { left: 12, right: 16, top: 56, bottom: 0, containLabel: true },
// 为居中显示的日期预留两端空间,避免裁切或挤掉相邻标签。
grid: { left: 0, right: 0, top: 56, bottom: 0, outerBoundsMode: 'same', outerBoundsContain: 'axisLabel' },
xAxis: {
type: 'category',
data: props.option.xData,
Expand Down
7 changes: 5 additions & 2 deletions ui/src/views/VIEW_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,11 @@ MCP 配置入口使用独立权限。导出 Skills 权限已定义,知识库

四类知识库创建入口集中在 `knowledge/create-knowledge/`:`BaseKnowledgeDialog`、
`WebKnowledgeDrawer`、`LarkKnowledgeDialog`、`WorkflowKnowledgeDialog`。
`KnowledgeBaseForm` 负责名称、描述及 Embedding 选择,内部按范围查询模型;未选择时默认首个可用模型,
刷新不覆盖用户选择。创建浮层接收完整 Knowledge API,工作流创建使用其 `postKnowledgeWorkflow`。
`KnowledgeBaseForm` 负责名称、描述及 Embedding 选择,内部按范围查询模型;`mode` 默认为 `create`,
未选择时默认首个可用模型,刷新不覆盖用户选择;基础设置传入 `mode="setting"`,不自动选择模型,保留详情空值。
创建浮层接收完整 Knowledge API,工作流创建使用其 `postKnowledgeWorkflow`。
导入创建成功后先刷新基础资料权限与列表,再提示设置向量模型并向量化文档;确认后按知识库类型进入当前范围的基础设置页,关闭提示保留在当前页。
“导出知识库”先弹窗确认是否同时导出源文件,默认不勾选;确认后通过当前范围 API 导出,成功关闭、失败保留选项,关闭后清理选择。文档 Excel、ZIP 仍直接导出。

`DocumentStrategyForm` 由 Web 创建、文档上传及策略设置复用;视觉增强仅在启用、切换策略或回填启用配置时
查询对应模型/工具,刷新模型不请求工具。Web 创建两步,策略设置回填独立草稿并单独保存 `doc_strategy`,下次同步生效。
Expand Down
6 changes: 4 additions & 2 deletions ui/src/views/knowledge-detail/setting/base/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import { isWorkspaceResource, isWorkspaceSharedResource, isSystemResource } from
import KnowledgeBaseForm from '@/views/knowledge/create-knowledge/components/KnowledgeBaseForm.vue'
import { useKnowledgeDetailContext } from '../../context'

const canEdit = () => !isWorkspaceSharedResource() && (isSystemResource() ? perm.knowledge.system.settingEdit() : !isWorkspaceResource() || perm.knowledge.workspace.settingEdit(knowledgeId.value))
const canEdit = () =>
!isWorkspaceSharedResource() &&
(isSystemResource() ? perm.knowledge.system.settingEdit() : !isWorkspaceResource() || perm.knowledge.workspace.settingEdit(knowledgeId.value))

defineOptions({ name: 'KnowledgeBaseSettingView' })

Expand Down Expand Up @@ -136,7 +138,7 @@ defineProps<ResourceDetailPageProps>()

<template>
<div v-loading="saving" class="max-w-200 pb-6">
<KnowledgeBaseForm ref="baseFormRef" />
<KnowledgeBaseForm ref="baseFormRef" mode="setting" />
<el-form
v-if="knowledge"
class="mt-4"
Expand Down
29 changes: 25 additions & 4 deletions ui/src/views/knowledge/components/ButtonCreateKnowledge.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
<script setup lang="ts">
import { computed, ref, useTemplateRef, type CSSProperties } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import type { UploadFile, UploadInstance } from 'element-plus'
import KnowledgeApi from '@/api/admin/workspace/knowledge/knowledge'
import type SystemSharedKnowledgeApi from '@/api/admin/system/shared-resources/knowledge/knowledge'
import { KNOWLEDGE_TYPE } from '@/api/enums'
import { KNOWLEDGE_TYPE_MAP } from '@/constants/knowledge'
import { useStore } from '@/stores'
import { MsgSuccess } from '@/utils/message'
import { MsgConfirm } from '@/utils/message'
import { isSystemSharedResource } from '@/utils/resource-context'
import CreateBaseKnowledgeDialog from '../create-knowledge/BaseKnowledgeDialog.vue'
import CreateWebKnowledgeDrawer from '../create-knowledge/WebKnowledgeDrawer.vue'
import CreateLarkKnowledgeDialog from '../create-knowledge/LarkKnowledgeDialog.vue'
Expand All @@ -25,6 +28,8 @@ const props = withDefaults(
{ api: () => KnowledgeApi, trigger: 'click', fitTriggerWidth: false },
)
const { auth } = useStore()
const route = useRoute()
const router = useRouter()

defineSlots<{
/** 创建菜单触发器,只能渲染一个有效根节点 */
Expand Down Expand Up @@ -78,14 +83,30 @@ const importing = ref(false)
function handleImportCreate(file: UploadFile) {
if (!file.raw || importing.value) return
importing.value = true
return props.api.postKnowledgeImport(file.raw, props.folderId)
.then(() => {
return props.api
.postKnowledgeImport(file.raw, props.folderId)
.then((knowledge) => {
// 先刷新新资源权限,再通知列表加载导入的知识库。
return auth.loadAuthBaseProfile().then(() => {
MsgSuccess('导入成功')
emit('refresh')
return MsgConfirm('提示', '导入创建知识库成功,文档数据未向量化,请先设置知识库的向量模型,并对文档进行向量化操作', {
showCancelButton: false,
confirmButtonText: '确定',
confirmButtonType: 'primary',
}).then(() => {
const routePrefix = isSystemSharedResource() ? 'system-shared-knowledge' : 'workspace-knowledge'
return router.push({
name: `${routePrefix}-${knowledge.type === KNOWLEDGE_TYPE.BASE ? 'setting' : 'base-setting'}`,
params: {
...(isSystemSharedResource() ? {} : { workspaceId: route.params.workspaceId }),
knowledgeId: knowledge.knowledge_id,
type: KNOWLEDGE_TYPE_MAP[knowledge.type],
},
})
})
})
})
.catch(() => {})
.finally(() => {
importing.value = false
importUploadRef.value?.clearFiles()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import SelectModel from '@/components/business/select-model/index.vue'
import { isSystemResource, isSystemSharedResource, isWorkspaceSharedResource } from '@/utils/resource-context'

defineOptions({ name: 'KnowledgeBaseForm' })
defineProps<{ disabled?: boolean }>()
const props = withDefaults(defineProps<{ mode?: 'create' | 'setting'; disabled?: boolean }>(), {
mode: 'create',
})

type KnowledgeBaseDraft = Pick<KnowledgeCreatePayload, 'name' | 'desc' | 'embedding_model_id'>

Expand All @@ -32,7 +34,7 @@ function reset() {
Object.assign(form, {
name: '',
desc: '',
embedding_model_id: modelOptions.value.find((model) => model.status === MODEL_STATUS.SUCCESS)?.id ?? '',
embedding_model_id: props.mode === 'create' ? (modelOptions.value.find((model) => model.status === MODEL_STATUS.SUCCESS)?.id ?? '') : '',
})
formRef.value?.clearValidate()
}
Expand All @@ -52,8 +54,8 @@ function loadModelOptions() {
.then(([models, providers]) => {
modelOptions.value = models
providerOptions.value = providers
// 新建时默认选择首个可用模型,刷新选项时保留已有选择和详情回填值。
if (!form.embedding_model_id) {
// 仅新建时默认选择首个可用模型;设置时保留详情回填值,包括空值。
if (props.mode === 'create' && !form.embedding_model_id) {
form.embedding_model_id = models.find((model) => model.status === MODEL_STATUS.SUCCESS)?.id ?? ''
}
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { computed, useTemplateRef } from 'vue'
import { computed, ref, useTemplateRef } from 'vue'
import type KnowledgeApi from '@/api/admin/workspace/knowledge/knowledge'
import type { KnowledgeItem } from '@/api/types'
import type SystemResourceKnowledgeApi from '@/api/admin/system/resource-management/knowledge/knowledge'
Expand All @@ -25,15 +25,41 @@ const exportOptions = [
{ label: '导出知识库', method: 'exportKnowledge' },
] as const

const exportDialogVisible = ref(false)
const withSourceFile = ref(false)

function handleExportKnowledge(method: (typeof exportOptions)[number]['method']) {
if (loading.value) return
if (method === 'exportKnowledge') {
exportDialogVisible.value = true
return
}
loading.value = true
return props.api[method](props.knowledge.id, props.knowledge.name)
.catch(() => {})
.finally(() => {
loading.value = false
})
}

/* 确认知识库压缩包是否包含源文件 */
function handleConfirmExport() {
if (loading.value) return
loading.value = true
return props.api
.exportKnowledge(props.knowledge.id, props.knowledge.name, withSourceFile.value)
.then((success) => {
if (success) exportDialogVisible.value = false
})
.catch(() => {})
.finally(() => {
loading.value = false
})
}

function handleExportDialogClosed() {
withSourceFile.value = false
}
</script>

<template>
Expand Down Expand Up @@ -63,4 +89,18 @@ function handleExportKnowledge(method: (typeof exportOptions)[number]['method'])
</template>
</MkDropdown>
</MkDropdownItem>

<MkDialog v-model="exportDialogVisible" title="导出知识库" width="420" @closed="handleExportDialogClosed">
<div v-loading="loading">
<!-- 选择是否同时导出源文件 -->
<el-checkbox v-model="withSourceFile">同时导出源文件</el-checkbox>
<p class="ml-6 text-N600">勾选后将原始文件一并打包至 ZIP,导入时可自动恢复文件关联;不勾选,则仅导出文本内容。</p>
</div>
<template #footer>
<!-- 取消导出知识库 -->
<el-button plain :disabled="loading" @click="exportDialogVisible = false">取消</el-button>
<!-- 确认导出知识库 -->
<el-button type="primary" :loading="loading" @click="handleConfirmExport">导出</el-button>
</template>
</MkDialog>
</template>
Loading