Skip to content

Commit be7a6e9

Browse files
feat: document
1 parent ae15187 commit be7a6e9

14 files changed

Lines changed: 329 additions & 161 deletions

File tree

‎ui/src/api/admin/workspace/knowledge/document.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,15 @@ const putLarkDocumentSync = (knowledgeId: string, documentId: string) =>
7575
const putMulLarkSyncDocument = (knowledgeId: string, documentIds: string[]) =>
7676
put<{ id_list: string[] }, boolean>(`/workspace/${getWorkspaceId()}/knowledge/lark/${knowledgeId}/_batch`, { id_list: documentIds })
7777

78-
/** 保存单个文档的召回及来源设置。 */
78+
/** 单个文档设置。 */
7979
const putDocumentSetting = (knowledgeId: string, documentId: string, data: DocumentSettingPayload) =>
8080
put(`${getPrefix(knowledgeId)}/${documentId}`, data)
8181

82-
/** 批量保存文档召回设置。 */
82+
/** 批量文档设置。 */
8383
const putBatchDocumentSetting = (knowledgeId: string, documentIds: string[], data: DocumentSettingPayload) =>
8484
put(`${getPrefix(knowledgeId)}/batch_hit_handling`, { ...data, id_list: documentIds })
8585

86-
/** 将选中文档迁移至目标知识库。 */
86+
/** 批量/单个迁移至目标知识库。 */
8787
const putMigrateDocuments = (knowledgeId: string, targetKnowledgeId: string, documentIds: string[]) =>
8888
put(`${getPrefix(knowledgeId)}/migrate/${targetKnowledgeId}`, documentIds)
8989

‎ui/src/components/business/generate-questions/GenerateQuestionsDialog.vue‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ defineExpose({ open, close })
9595

9696
<template>
9797
<MkDialog v-model="visible" title="生成问题" @closed="emit('closed')">
98-
<el-form ref="formRef" :model="form" label-position="top" v-loading="loading || modelLoading" @submit.prevent>
98+
<el-form ref="formRef" :model="form" label-position="top" require-asterisk-position="right" v-loading="loading || modelLoading" @submit.prevent>
9999
<el-alert :closable="false" :title="promptTip" type="primary" class="mb-4! items-start! whitespace-pre-line" show-icon>
100100
<template #icon><MkIcon name="icon_info_filled" class="mt-2" /></template>
101101
</el-alert>

‎ui/src/components/mk-dynamics-form/items/knowledge/Knowledge.vue‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ const selectedKnowledgeIds = computed({
3535
</div>
3636
</el-option>
3737
<template #label="{ label, value }">
38-
<span class="inline-flex max-w-full items-center gap-2">
39-
<KnowledgeIcon :type="knowledgeById.get(value)?.type" :size="14" class="shrink-0" style="--el-avatar-border-radius: 4px" />
38+
<span class="flex-align-center gap-2">
39+
<KnowledgeIcon :type="knowledgeById.get(value)?.type" :size="16" class="shrink-0 small" />
4040
<span class="truncate" :title="label">{{ label }}</span>
4141
</span>
4242
</template>

‎ui/src/views/VIEW_README.md‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,10 @@ Web 来源地址与选择器仅在单项设置中编辑,批量设置不展示
717717
`MigrateDocumentAction` 选择目标知识库,`DocumentTagsAction` 添加已有标签和移除文档标签关联;
718718
生成问题复用公共配置弹窗,其余 Action 按下文维护各自专属弹窗。组件接收完整 Document API、知识库 ID、文档 ID 或文档数组及禁用状态,
719719
点击时快照本次操作对象,内部管理弹窗和请求,成功后通过 `refresh` 通知页面刷新,失败保留输入。
720+
迁移操作集中在 `document/action-dropdown/migrate/`,`MigrateDocumentAction.vue` 负责入口与弹窗按需挂载,
721+
`DocumentMigrateDialog.vue` 负责目标知识库查询、选择及迁移请求;关闭动画结束后卸载,失败保留输入。
722+
Action 继续通过上层 `action-dropdown/index.ts` 导出,单项与批量入口共用;入口文案由必填 `label` 传入,
723+
图标由可选 `icon` 传入,不传时不显示图标。
720724
单项向量化仅传 `document`,内部判断排队或执行状态,固定展示行内图标按钮,分别调用单项向量化和取消接口。
721725
批量向量化仅传 `document-ids`,使用独立的 `BatchEmbeddingAction` 普通按钮;
722726
批量取消向量化继续使用 `BatchCancelTaskAction` 菜单项,单项和批量请求均通过 `v-model:loading` 共用页面操作状态。
@@ -730,7 +734,15 @@ Action 仍通过上层 `action-dropdown/index.ts` 导出,弹窗仅在目录内
730734
提交同一文档批量接口并通过 `refresh` 刷新状态;通过 `v-model:loading` 复用页面操作状态。
731735
公共弹窗按需挂载、关闭后卸载,不负责选择提交接口。当前尚无段落页,后续段落入口复用公共
732736
弹窗时关闭 `showParagraphScope`,由段落 Action 提交段落接口,不扩展公共弹窗的接口分支。
733-
设置组件通过 `batch` 区分单项与批量,标签组件通过 `manageTags` 区分标签管理与批量添加。
737+
设置操作集中在 `document/action-dropdown/setting/`,通过上层 `index.ts` 导出两个入口。
738+
`SettingDocumentAction` 接收单个 `document`,展示菜单项;`BatchSettingDocumentAction` 接收
739+
`documentIds`,展示批量设置按钮。入口文案由 `label` 传入,单项图标由可选 `icon` 传入。
740+
两个入口通过 `v-model:loading` 共用页面操作状态,打开时固定操作目标,分别调用单项和批量设置接口。
741+
共用的 `DocumentSettingDialog.vue` 负责表单回填、校验和提交数据,按需挂载、关闭动画结束后卸载;
742+
弹窗通过 `batch` 参数区分批量模式,批量入口显式传入;文档地址和选择器仅在 `!batch` 且为 Web 知识库时显示。
743+
单项保留文档原有 `meta`,批量使用默认配置并将 `allow_download`
744+
放在顶层。请求与成功关闭由 Action 负责,成功通知页面刷新,失败保留表单。
745+
标签组件通过 `manageTags` 区分标签管理与批量添加。
734746
分词索引集中在 `document/action-dropdown/tokenize/`:`TokenizeDocumentAction` 接收单个 `document`,
735747
按运行状态调用单项分词或取消接口;`BatchTokenizeAction` 接收 `documentIds`,仅调用批量分词接口。
736748
两个 Action 均处理全部分段状态,通过 `v-model:loading` 共用页面操作状态,成功后通知页面刷新。

‎ui/src/views/knowledge-detail/library/document/action-dropdown/DocumentTagsAction.vue‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ function handleClosed() {
104104
@click="handleOpenDialog"
105105
/>
106106
<MkDialog v-model="visible" :title="manage ? '标签设置' : '添加标签'" :show-close="!loading && !optionLoading" @closed="handleClosed">
107-
<el-form label-position="top" @submit.prevent>
107+
<el-form label-position="top" require-asterisk-position="right" @submit.prevent>
108108
<el-form-item label="标签">
109109
<el-select
110110
v-model="selectedTagIds"

‎ui/src/views/knowledge-detail/library/document/action-dropdown/MigrateDocumentAction.vue‎

Lines changed: 0 additions & 82 deletions
This file was deleted.

‎ui/src/views/knowledge-detail/library/document/action-dropdown/index.ts‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ export { default as BatchGenerateQuestionsAction } from './generate-questions/Ba
88
export { default as DownloadDocumentAction } from './DownloadDocumentAction.vue'
99
export { default as ExportDocumentAction } from './export/ExportDocumentAction.vue'
1010
export { default as BatchExportDocumentAction } from './export/BatchExportDocumentAction.vue'
11-
export { default as MigrateDocumentAction } from './MigrateDocumentAction.vue'
11+
export { default as MigrateDocumentAction } from './migrate/MigrateDocumentAction.vue'
1212
export { default as ReplaceDocumentAction } from './ReplaceDocumentAction.vue'
13-
export { default as SettingDocumentAction } from './SettingDocumentAction.vue'
13+
export { default as SettingDocumentAction } from './setting/SettingDocumentAction.vue'
14+
export { default as BatchSettingDocumentAction } from './setting/BatchSettingDocumentAction.vue'
1415
export { default as SyncDocumentAction } from './sync/SyncDocumentAction.vue'
1516
export { default as BatchSyncDocumentAction } from './sync/BatchSyncDocumentAction.vue'
1617
export { default as TokenizeDocumentAction } from './tokenize/TokenizeDocumentAction.vue'
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<script setup lang="ts">
2+
import { computed, reactive, ref, useTemplateRef } from 'vue'
3+
import type { FormInstance, FormRules } from 'element-plus'
4+
import type { KnowledgeItem } from '@/api/types'
5+
import KnowledgeApi from '@/api/admin/workspace/knowledge/knowledge'
6+
import type DocumentApi from '@/api/admin/workspace/knowledge/document'
7+
import { MsgSuccess } from '@/utils/message'
8+
9+
defineOptions({ name: 'DocumentMigrateDialog' })
10+
const props = defineProps<{ api: typeof DocumentApi; knowledgeId: string }>()
11+
const emit = defineEmits<{ refresh: []; closed: [] }>()
12+
const visible = ref(false)
13+
const loading = defineModel<boolean>('loading', { default: false })
14+
const optionLoading = ref(false)
15+
const knowledgeOptions = ref<KnowledgeItem[]>([])
16+
const knowledgeById = computed(() => new Map(knowledgeOptions.value.map((knowledge) => [knowledge.id, knowledge])))
17+
const migrateFormRef = useTemplateRef<FormInstance>('migrateFormRef')
18+
const migrateForm = reactive({ targetKnowledgeId: '' })
19+
const migrateRules: FormRules<typeof migrateForm> = {
20+
targetKnowledgeId: [{ required: true, message: '请选择知识库', trigger: 'change' }],
21+
}
22+
const targetDocumentIds = ref<string[]>([])
23+
24+
// 打开迁移弹窗,固定本次文档并查询目标知识库。
25+
function open(documentIds: string[]) {
26+
if (loading.value || optionLoading.value || !documentIds.length) return
27+
targetDocumentIds.value = [...documentIds]
28+
visible.value = true
29+
optionLoading.value = true
30+
KnowledgeApi.getAllKnowledge()
31+
.then((knowledge) => {
32+
knowledgeOptions.value = knowledge.filter(({ id }) => id !== props.knowledgeId)
33+
})
34+
.catch(() => {
35+
// 请求层统一提示错误,保留当前输入。
36+
})
37+
.finally(() => {
38+
optionLoading.value = false
39+
})
40+
}
41+
42+
// 迁移成功后关闭并通知页面刷新,失败保留选择。
43+
async function handleSubmit() {
44+
if (loading.value || optionLoading.value || !(await migrateFormRef.value?.validate().catch(() => false))) return
45+
loading.value = true
46+
return props.api
47+
.putMigrateDocuments(props.knowledgeId, migrateForm.targetKnowledgeId, targetDocumentIds.value)
48+
.then(() => {
49+
MsgSuccess('迁移成功')
50+
visible.value = false
51+
emit('refresh')
52+
})
53+
.catch(() => {
54+
// 请求层统一提示错误,保留当前输入。
55+
})
56+
.finally(() => {
57+
loading.value = false
58+
})
59+
}
60+
61+
defineExpose({ open })
62+
</script>
63+
64+
<template>
65+
<MkDialog v-model="visible" title="文档迁移到" @closed="emit('closed')">
66+
<el-form ref="migrateFormRef" :model="migrateForm" :rules="migrateRules" label-position="top" require-asterisk-position="right" @submit.prevent>
67+
<el-form-item label="选择知识库" prop="targetKnowledgeId">
68+
<el-select v-model="migrateForm.targetKnowledgeId" fit-input-width filterable placeholder="请选择知识库" :loading="optionLoading">
69+
<template v-for="target in knowledgeOptions" :key="target.id">
70+
<el-option :label="target.name" :value="target.id">
71+
<div class="flex-align-center min-w-0 gap-2">
72+
<KnowledgeIcon :type="target.type" :size="20" class="shrink-0" />
73+
<span class="truncate" :title="target.name">{{ target.name }}</span>
74+
</div>
75+
</el-option>
76+
</template>
77+
<template #label="{ label, value }">
78+
<span class="flex-align-center gap-2">
79+
<KnowledgeIcon :type="knowledgeById.get(value)?.type" :size="20" class="shrink-0" />
80+
<span class="truncate" :title="label">{{ label }}</span>
81+
</span>
82+
</template>
83+
</el-select>
84+
</el-form-item>
85+
</el-form>
86+
<template #footer>
87+
<!-- 取消文档迁移 -->
88+
<el-button plain :disabled="loading || optionLoading" @click="visible = false">取消</el-button>
89+
<!-- 确认迁移文档 -->
90+
<el-button type="primary" :loading="loading" :disabled="optionLoading" @click="handleSubmit">确认</el-button>
91+
</template>
92+
</MkDialog>
93+
</template>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<script setup lang="ts">
2+
import { nextTick, ref, useTemplateRef } from 'vue'
3+
import type DocumentApi from '@/api/admin/workspace/knowledge/document'
4+
import DocumentMigrateDialog from './DocumentMigrateDialog.vue'
5+
6+
defineOptions({ name: 'MigrateDocumentAction' })
7+
const props = defineProps<{ api: typeof DocumentApi; knowledgeId: string; documentIds: string[]; label: string; icon?: string; disabled?: boolean }>()
8+
const emit = defineEmits<{ refresh: [] }>()
9+
const loading = ref(false)
10+
11+
// 迁移弹窗按需挂载,关闭动画结束后卸载。
12+
const dialogMounted = ref(false)
13+
const migrateDialogRef = useTemplateRef<InstanceType<typeof DocumentMigrateDialog>>('migrateDialogRef')
14+
15+
function handleOpenDialog() {
16+
const documentIds = [...props.documentIds]
17+
dialogMounted.value = true
18+
return nextTick(() => migrateDialogRef.value?.open(documentIds))
19+
}
20+
21+
function handleDialogClosed() {
22+
dialogMounted.value = false
23+
}
24+
</script>
25+
26+
<template>
27+
<!-- 文档迁移入口 -->
28+
<MkAction :label="label" :icon="icon" :disabled="disabled || loading" @click="handleOpenDialog" />
29+
<DocumentMigrateDialog
30+
v-if="dialogMounted"
31+
ref="migrateDialogRef"
32+
v-model:loading="loading"
33+
:api="api"
34+
:knowledge-id="knowledgeId"
35+
@refresh="emit('refresh')"
36+
@closed="handleDialogClosed"
37+
/>
38+
</template>
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<script setup lang="ts">
2+
import { nextTick, ref, useTemplateRef } from 'vue'
3+
import type { DocumentSettingPayload } from '@/api/types'
4+
import type DocumentApi from '@/api/admin/workspace/knowledge/document'
5+
import { MsgSuccess } from '@/utils/message'
6+
import DocumentSettingDialog from './DocumentSettingDialog.vue'
7+
8+
defineOptions({ name: 'BatchSettingDocumentAction' })
9+
const props = defineProps<{ api: typeof DocumentApi; knowledgeId: string; documentIds: string[]; label: string; disabled?: boolean }>()
10+
const loading = defineModel<boolean>('loading', { default: false })
11+
const emit = defineEmits<{ refresh: [] }>()
12+
13+
// 打开设置时固定操作对象,弹窗关闭后卸载。
14+
const dialogMounted = ref(false)
15+
const settingDialogRef = useTemplateRef<InstanceType<typeof DocumentSettingDialog>>('settingDialogRef')
16+
const targetKnowledgeId = ref('')
17+
const targetDocumentIds = ref<string[]>([])
18+
19+
function handleOpenDialog() {
20+
if (props.disabled || loading.value || dialogMounted.value || !props.documentIds.length) return
21+
targetKnowledgeId.value = props.knowledgeId
22+
targetDocumentIds.value = [...props.documentIds]
23+
dialogMounted.value = true
24+
return nextTick(() => settingDialogRef.value?.open())
25+
}
26+
27+
// 设置成功后关闭弹窗并刷新列表,失败保留表单。
28+
function handleSubmit(data: DocumentSettingPayload) {
29+
if (loading.value) return
30+
loading.value = true
31+
return props.api
32+
.putBatchDocumentSetting(targetKnowledgeId.value, targetDocumentIds.value, data)
33+
.then(() => {
34+
MsgSuccess('设置成功')
35+
settingDialogRef.value?.close()
36+
emit('refresh')
37+
})
38+
.catch(() => {
39+
// 请求层统一提示错误,保留当前输入。
40+
})
41+
.finally(() => {
42+
loading.value = false
43+
})
44+
}
45+
46+
function handleDialogClosed() {
47+
dialogMounted.value = false
48+
}
49+
</script>
50+
51+
<template>
52+
<!-- 批量文档设置 -->
53+
<el-button plain :disabled="disabled || loading" @click="handleOpenDialog">{{ label }}</el-button>
54+
<DocumentSettingDialog v-if="dialogMounted" ref="settingDialogRef" batch :loading="loading" @submit="handleSubmit" @closed="handleDialogClosed" />
55+
</template>

0 commit comments

Comments
 (0)