perf: Knowledge base workflow document import
Some checks are pending
sync2gitee / repo-sync (push) Waiting to run
Typos Check / Spell Check with Typos (push) Waiting to run

This commit is contained in:
wangdan-fit2cloud 2025-12-01 18:28:45 +08:00
parent f29a8c3701
commit 4b417edbbf
11 changed files with 229 additions and 113 deletions

View File

@ -113,7 +113,7 @@ const DocumentRouter = {
name: 'knowledgeWorkflowSetting', name: 'knowledgeWorkflowSetting',
meta: { meta: {
title: 'views.workflow.workflow', title: 'views.workflow.workflow',
icon: 'app-workflow', icon: 'app-problems',
activeMenu: '/knowledge', activeMenu: '/knowledge',
sameRoute: 'knowledge', sameRoute: 'knowledge',
permission: [ permission: [
@ -202,9 +202,7 @@ const DocumentRouter = {
}), }),
}, },
redirect: (menu: any) => { redirect: (menu: any) => {
const from = 'workspace' return `/knowledge/${menu.params.id}/${menu.params.folderId}/workflow`
console.log(`/knowledge/${from}/${menu.params.id}/${menu.params.folderId}/workflow`)
return `/knowledge/${from}/${menu.params.id}/${menu.params.folderId}/workflow`
}, },
component: () => import('@/views/knowledge/index.vue'), component: () => import('@/views/knowledge/index.vue'),
}, },

View File

@ -33,13 +33,22 @@ const ModelRouter = {
component: () => import('@/views/document/UploadDocument.vue'), component: () => import('@/views/document/UploadDocument.vue'),
hidden: true, hidden: true,
}, },
// 上传文档 - 飞书文档
{ {
path: '/knowledge/import/:folderId/:type', path: '/knowledge/import/lark/:knowledgeId',
name: 'ImportLarkDocument', name: 'ImportLarkDocument',
meta: { activeMenu: '/knowledge' }, meta: { activeMenu: '/knowledge' },
component: () => import('@/views/document/ImportLarkDocument.vue'), component: () => import('@/views/document/ImportLarkDocument.vue'),
hidden: true, hidden: true,
}, },
// 上传文档 - 工作流
{
path: '/knowledge/import/workflow/:knowledgeId',
name: 'ImportWorkflowDocument',
meta: { activeMenu: '/knowledge' },
component: () => import('@/views/document/ImportWorkflowDocument.vue'),
hidden: true,
},
], ],
} }

View File

@ -38,7 +38,7 @@ export const routes: Array<RouteRecordRaw> = [
}, },
// 知识库工作流 // 知识库工作流
{ {
path: '/knowledge/:from/:id/:folderId/workflow', path: '/knowledge/:id/:folderId/workflow',
name: 'KnowledgeWorkflow', name: 'KnowledgeWorkflow',
meta: { activeMenu: '/knowledge' }, meta: { activeMenu: '/knowledge' },
component: () => import('@/views/knowledge-workflow/index.vue'), component: () => import('@/views/knowledge-workflow/index.vue'),

View File

@ -1,13 +1,13 @@
<template> <template>
<div class="create-knowledge p-12-24"> <div class="upload-document p-12-24">
<div class="flex align-center mb-16"> <div class="flex align-center mb-16">
<back-button to="-1" style="margin-left: -4px"></back-button> <back-button to="-1" style="margin-left: -4px"></back-button>
<h3 style="display: inline-block">{{ $t('views.document.importDocument') }}</h3> <h3 style="display: inline-block">{{ $t('views.document.importDocument') }}</h3>
</div> </div>
<el-card style="--el-card-padding: 0"> <el-card style="--el-card-padding: 0">
<div class="create-knowledge__main flex" v-loading="loading"> <div class="upload-document__main flex" v-loading="loading">
<div class="create-knowledge__component main-calc-height"> <div class="upload-document__component main-calc-height">
<div class="upload-document p-24" style="min-width: 850px"> <div class="upload-component p-24" style="min-width: 850px">
<h4 class="title-decoration-1 mb-8"> <h4 class="title-decoration-1 mb-8">
{{ $t('views.document.feishu.selectDocument') }} {{ $t('views.document.feishu.selectDocument') }}
</h4> </h4>
@ -127,8 +127,8 @@
</div> </div>
</div> </div>
</el-card> </el-card>
<div class="create-knowledge__footer text-right border-t"> <div class="upload-document__footer text-right border-t">
<el-button @click="router.go(-1)">{{ $t('common.cancel') }}</el-button> <el-button @click="back">{{ $t('common.cancel') }}</el-button>
<el-button @click="submit" type="primary" :disabled="disabled"> <el-button @click="submit" type="primary" :disabled="disabled">
{{ $t('views.document.buttons.import') }} {{ $t('views.document.buttons.import') }}
@ -147,7 +147,8 @@ import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
const router = useRouter() const router = useRouter()
const route = useRoute() const route = useRoute()
const { const {
query: { id, folder_token }, // idknowledgeIDid folder_tokentoken params: { knowledgeId },
query: { folder_token }, // idknowledgeIDid folder_tokentoken
} = route } = route
const apiType = computed(() => { const apiType = computed(() => {
if (route.path.includes('shared')) { if (route.path.includes('shared')) {
@ -158,7 +159,6 @@ const apiType = computed(() => {
return 'workspace' return 'workspace'
} }
}) })
const knowledgeId = id as string
const folderToken = folder_token as string const folderToken = folder_token as string
const loading = ref(false) const loading = ref(false)
@ -250,7 +250,7 @@ function submit() {
.then(() => { .then(() => {
MsgSuccess(t('views.document.tip.importMessage')) MsgSuccess(t('views.document.tip.importMessage'))
disabled.value = false disabled.value = false
router.go(-1) back()
}) })
.catch((err: any) => { .catch((err: any) => {
console.error('Failed to load tree nodes:', err) console.error('Failed to load tree nodes:', err)
@ -265,37 +265,6 @@ function back() {
router.go(-1) router.go(-1)
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss">
.create-knowledge { @use './index.scss';
&__component {
width: 100%;
margin: 0 auto;
overflow: hidden;
}
&__footer {
padding: 16px 24px;
position: fixed;
bottom: 0;
left: 0;
background: #ffffff;
width: 100%;
box-sizing: border-box;
}
.upload-document {
width: 70%;
margin: 0 auto;
margin-bottom: 20px;
}
}
.xlsx-icon {
svg {
width: 24px;
height: 24px;
stroke: #000000 !important;
fill: #ffffff !important;
}
}
</style> </style>

View File

@ -0,0 +1,134 @@
<template>
<div class="upload-document p-12-24">
<div class="flex align-center mb-16">
<back-button to="-1" style="margin-left: -4px"></back-button>
<h3 style="display: inline-block">{{ $t('views.document.importDocument') }}</h3>
</div>
<el-card style="--el-card-padding: 0">
<div class="upload-document__main flex" v-loading="loading">
<div class="upload-document__component main-calc-height">
<div class="upload-component p-24" style="min-width: 850px">
<keep-alive>
<component
ref="ActionRef"
:is="ak[active]"
v-model:loading="loading"
:workflow="_workflow"
:knowledge_id="knowledgeId"
:id="action_id"
></component>
</keep-alive>
</div>
</div>
</div>
</el-card>
<div class="upload-document__footer text-right border-t">
<el-button :disabled="loading" @click="router.go(-1)">{{ $t('common.cancel') }}</el-button>
<el-button
v-if="base_form_list.length > 0 && active == 'knowledge_base'"
:loading="loading"
@click="up"
>
{{ $t('views.document.buttons.prev') }}</el-button
>
<el-button
v-if="base_form_list.length > 0 && active == 'data_source'"
:disabled="loading"
@click="next"
>
{{ $t('views.document.buttons.next') }}
</el-button>
<el-button
v-if="base_form_list.length > 0 ? active == 'knowledge_base' : true"
@click="upload"
type="primary"
:disabled="loading"
>
{{ $t('views.document.buttons.import') }}
</el-button>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, ref, provide, type Ref, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import DataSource from '@/views/knowledge-workflow/component/action/DataSource.vue'
import Result from '@/views/knowledge-workflow/component/action/Result.vue'
import applicationApi from '@/api/application/application'
import KnowledgeBase from '@/views/knowledge-workflow/component/action/KnowledgeBase.vue'
import { loadSharedApi } from '@/utils/dynamics-api/shared-api.ts'
import { WorkflowType } from '@/enums/application'
provide('upload', (file: any, loading?: Ref<boolean>) => {
return applicationApi.postUploadFile(file, knowledgeId as string, 'KNOWLEDGE', loading)
})
const router = useRouter()
const route = useRoute()
const {
params: { knowledgeId },
} = route
const apiType = computed(() => {
if (route.path.includes('shared')) {
return 'systemShare'
} else if (route.path.includes('resource-management')) {
return 'systemManage'
} else {
return 'workspace'
}
})
const ak = {
data_source: DataSource,
knowledge_base: KnowledgeBase,
result: Result,
}
const loading = ref(false)
const ActionRef = ref()
const action_id = ref<string>()
const form_data = ref<any>({})
const active = ref<'data_source' | 'knowledge_base' | 'result'>('data_source')
const _workflow = ref<any>(null)
const base_form_list = computed(() => {
const kBase = _workflow.value?.nodes?.find((n: any) => n.type === WorkflowType.KnowledgeBase)
if (kBase) {
return kBase.properties.user_input_field_list
}
return []
})
const next = () => {
ActionRef.value.validate().then(() => {
form_data.value[active.value] = ActionRef.value.get_data()
active.value = 'knowledge_base'
})
}
const up = () => {
ActionRef.value.validate().then(() => {
active.value = 'data_source'
})
}
const upload = () => {
ActionRef.value.validate().then(() => {
form_data.value[active.value] = ActionRef.value.get_data()
loadSharedApi({ type: 'knowledge', systemType: apiType.value })
.workflowUpload(knowledgeId, form_data.value, loading)
.then((ok: any) => {
router.go(-1)
})
})
}
function getDetail() {
loadSharedApi({ type: 'knowledge', systemType: apiType.value })
.getKnowledgeDetail(knowledgeId, loading)
.then((res: any) => {
_workflow.value = res.data.work_flow
})
}
onMounted(() => {
getDetail()
})
</script>
<style lang="scss">
@use './index.scss';
</style>

View File

@ -198,39 +198,6 @@ onUnmounted(() => {
clearStore() clearStore()
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss">
.upload-document { @use './index.scss';
&__steps {
min-width: 450px;
max-width: 800px;
width: 80%;
margin: 0 auto;
padding-right: 60px;
:deep(.el-step__line) {
left: 64% !important;
right: -33% !important;
}
}
&__component {
width: 100%;
margin: 0 auto;
overflow: hidden;
}
&__footer {
padding: 16px 24px;
position: fixed;
bottom: 0;
left: 0;
background: #ffffff;
width: 100%;
box-sizing: border-box;
}
.upload-component {
width: 70%;
margin: 0 auto;
margin-bottom: 20px;
}
}
</style> </style>

View File

@ -0,0 +1,21 @@
.upload-document {
&__component {
width: 100%;
margin: 0 auto;
overflow: hidden;
}
&__footer {
padding: 16px 24px;
position: fixed;
bottom: 0;
left: 0;
background: #ffffff;
width: 100%;
box-sizing: border-box;
}
.upload-component {
width: 70%;
margin: 0 auto;
margin-bottom: 20px;
}
}

View File

@ -29,15 +29,24 @@
type="primary" type="primary"
@click=" @click="
router.push({ router.push({
path: `/knowledge/import/${folderId}/${type}`, path: `/knowledge/import/lark/${id}`,
query: { query: {
id: id,
folder_token: knowledgeDetail?.meta.folder_token, folder_token: knowledgeDetail?.meta.folder_token,
}, },
}) })
" "
>{{ $t('views.document.importDocument') }} >{{ $t('views.document.importDocument') }}
</el-button> </el-button>
<el-button
v-if="knowledgeDetail?.type === 4 && permissionPrecise.doc_create(id)"
type="primary"
@click="
router.push({
path: `/knowledge/import/workflow/${id}`,
})
"
>{{ $t('views.document.importDocument') }}
</el-button>
<el-button <el-button
@click="batchRefresh" @click="batchRefresh"
:disabled="multipleSelection.length === 0" :disabled="multipleSelection.length === 0"
@ -132,9 +141,7 @@
clearable clearable
/> />
</div> </div>
<el-button @click="openTagDrawer" class="ml-12" <el-button @click="openTagDrawer" class="ml-12" v-if="permissionPrecise.tag_read(id)">
v-if="permissionPrecise.tag_read(id)"
>
{{ $t('views.document.tag.label') }} {{ $t('views.document.tag.label') }}
</el-button> </el-button>
</div> </div>
@ -481,7 +488,8 @@
></AppIcon> ></AppIcon>
{{ $t('views.document.generateQuestion.title') }} {{ $t('views.document.generateQuestion.title') }}
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item @click="openTagSettingDrawer(row)" <el-dropdown-item
@click="openTagSettingDrawer(row)"
v-if="permissionPrecise.doc_tag(id)" v-if="permissionPrecise.doc_tag(id)"
> >
<AppIcon iconName="app-tag" class="color-secondary"></AppIcon> <AppIcon iconName="app-tag" class="color-secondary"></AppIcon>
@ -605,7 +613,8 @@
<AppIcon iconName="app-sync" class="color-secondary"></AppIcon> <AppIcon iconName="app-sync" class="color-secondary"></AppIcon>
{{ $t('views.knowledge.setting.sync') }}</el-dropdown-item {{ $t('views.knowledge.setting.sync') }}</el-dropdown-item
> >
<el-dropdown-item @click="openTagSettingDrawer(row)" <el-dropdown-item
@click="openTagSettingDrawer(row)"
v-if="permissionPrecise.doc_tag(id)" v-if="permissionPrecise.doc_tag(id)"
> >
<AppIcon iconName="app-tag" class="color-secondary"></AppIcon> <AppIcon iconName="app-tag" class="color-secondary"></AppIcon>
@ -783,7 +792,8 @@ const MoreFilledPermission0 = (id: string) => {
permissionPrecise.value.doc_migrate(id) || permissionPrecise.value.doc_migrate(id) ||
(knowledgeDetail?.value.type === 1 && permissionPrecise.value.doc_sync(id)) || (knowledgeDetail?.value.type === 1 && permissionPrecise.value.doc_sync(id)) ||
(knowledgeDetail?.value.type === 2 && permissionPrecise.value.doc_sync(id)) || (knowledgeDetail?.value.type === 2 && permissionPrecise.value.doc_sync(id)) ||
permissionPrecise.value.doc_delete(id) || permissionPrecise.value.doc_tag(id) permissionPrecise.value.doc_delete(id) ||
permissionPrecise.value.doc_tag(id)
) )
} }

View File

@ -14,7 +14,7 @@
:is="ak[active]" :is="ak[active]"
v-model:loading="loading" v-model:loading="loading"
:workflow="_workflow" :workflow="_workflow"
:knowledge_id="_knowledge_id" :knowledge_id="id"
:id="action_id" :id="action_id"
></component> ></component>
</keep-alive> </keep-alive>
@ -53,12 +53,18 @@ import Result from '@/views/knowledge-workflow/component/action/Result.vue'
import applicationApi from '@/api/application/application' import applicationApi from '@/api/application/application'
import KnowledgeBase from '@/views/knowledge-workflow/component/action/KnowledgeBase.vue' import KnowledgeBase from '@/views/knowledge-workflow/component/action/KnowledgeBase.vue'
import { WorkflowType } from '@/enums/application' import { WorkflowType } from '@/enums/application'
import { loadSharedApi } from "@/utils/dynamics-api/shared-api.ts"; import { loadSharedApi } from '@/utils/dynamics-api/shared-api.ts'
import { useRoute } from "vue-router"; import { useRoute } from 'vue-router'
provide('upload', (file: any, loading?: Ref<boolean>) => { provide('upload', (file: any, loading?: Ref<boolean>) => {
return applicationApi.postUploadFile(file, _knowledge_id.value, 'KNOWLEDGE', loading) return applicationApi.postUploadFile(file, id, 'KNOWLEDGE', loading)
}) })
const route = useRoute() const route = useRoute()
const {
params: { id },
/*
id knowledge_id
*/
} = route as any
const ak = { const ak = {
data_source: DataSource, data_source: DataSource,
knowledge_base: KnowledgeBase, knowledge_base: KnowledgeBase,
@ -80,17 +86,14 @@ const form_data = ref<any>({})
const active = ref<'data_source' | 'knowledge_base' | 'result'>('data_source') const active = ref<'data_source' | 'knowledge_base' | 'result'>('data_source')
const drawerVisible = ref<boolean>(false) const drawerVisible = ref<boolean>(false)
const _workflow = ref<any>(null) const _workflow = ref<any>(null)
const _knowledge_id = ref<string>('')
const close = () => { const close = () => {
drawerVisible.value = false drawerVisible.value = false
_workflow.value = null _workflow.value = null
_knowledge_id.value = ''
active.value = 'data_source' active.value = 'data_source'
} }
const open = (workflow: any, knowledge_id: string) => { const open = (workflow: any) => {
drawerVisible.value = true drawerVisible.value = true
_workflow.value = workflow _workflow.value = workflow
_knowledge_id.value = knowledge_id
} }
const base_form_list = computed(() => { const base_form_list = computed(() => {
@ -115,7 +118,8 @@ const upload = () => {
ActionRef.value.validate().then(() => { ActionRef.value.validate().then(() => {
form_data.value[active.value] = ActionRef.value.get_data() form_data.value[active.value] = ActionRef.value.get_data()
loadSharedApi({ type: 'knowledge', systemType: apiType.value }) loadSharedApi({ type: 'knowledge', systemType: apiType.value })
.workflowAction(_knowledge_id.value, form_data.value, loading).then((ok: any) => { .workflowAction(id, form_data.value, loading)
.then((ok: any) => {
action_id.value = ok.data.id action_id.value = ok.data.id
active.value = 'result' active.value = 'result'
}) })

View File

@ -9,7 +9,9 @@
:other-params="{ current_workspace_id: workspace_id, current_knowledge_id: knowledge_id }" :other-params="{ current_workspace_id: workspace_id, current_knowledge_id: knowledge_id }"
> >
<template #default> <template #default>
<h4 class="title-decoration-1 mb-16 mt-4">{{ $t('views.tool.dataSource.selectDataSource') }}</h4> <h4 class="title-decoration-1 mb-16 mt-4">
{{ $t('views.tool.dataSource.selectDataSource') }}
</h4>
<el-form-item <el-form-item
:label="$t('views.tool.dataSource.title')" :label="$t('views.tool.dataSource.title')"
prop="node_id" prop="node_id"
@ -55,6 +57,12 @@ import useStore from '@/stores'
const { user } = useStore() const { user } = useStore()
const route = useRoute() const route = useRoute()
const props = defineProps<{
workflow: any
knowledge_id: string
loading: boolean
}>()
const apiType = computed(() => { const apiType = computed(() => {
if (route.path.includes('shared')) { if (route.path.includes('shared')) {
return 'systemShare' return 'systemShare'
@ -65,11 +73,7 @@ const apiType = computed(() => {
} }
}) })
const model_form_field = ref<Array<FormField>>([]) const model_form_field = ref<Array<FormField>>([])
const props = defineProps<{
workflow: any
knowledge_id: string
loading: boolean
}>()
const workspace_id = computed(() => { const workspace_id = computed(() => {
return user.getWorkspaceId() return user.getWorkspaceId()
}) })
@ -96,9 +100,6 @@ const form_data = computed({
const source_node_list = computed(() => { const source_node_list = computed(() => {
return props.workflow?.nodes?.filter((n: any) => n.properties.kind === WorkflowKind.DataSource) return props.workflow?.nodes?.filter((n: any) => n.properties.kind === WorkflowKind.DataSource)
}) })
const {
params: { id, from },
} = route as any
const sourceChange = (node_id: string) => { const sourceChange = (node_id: string) => {
base_form_data.value.node_id = node_id base_form_data.value.node_id = node_id
const n = source_node_list.value.find((n: any) => n.id == node_id) const n = source_node_list.value.find((n: any) => n.id == node_id)
@ -109,7 +110,7 @@ const sourceChange = (node_id: string) => {
: node_id : node_id
loadSharedApi({ type: 'knowledge', systemType: apiType.value }) loadSharedApi({ type: 'knowledge', systemType: apiType.value })
.getKnowledgeWorkflowFormList( .getKnowledgeWorkflowFormList(
id, props.knowledge_id,
[WorkflowType.DataSourceLocalNode, WorkflowType.DataSourceWebNode].includes(n.type) [WorkflowType.DataSourceLocalNode, WorkflowType.DataSourceWebNode].includes(n.type)
? 'local' ? 'local'
: 'tool', : 'tool',

View File

@ -166,7 +166,10 @@ const { theme } = useStore()
const router = useRouter() const router = useRouter()
const route = useRoute() const route = useRoute()
const { const {
params: { id, from, folderId }, params: { id, folderId },
/*
folderId 可以区分 resource-management shared还是 workspace
*/
} = route as any } = route as any
const apiType = computed(() => { const apiType = computed(() => {
if (route.path.includes('shared')) { if (route.path.includes('shared')) {
@ -373,7 +376,7 @@ const clickShowDebug = () => {
...workflow.get_base_node()?.properties.node_data, ...workflow.get_base_node()?.properties.node_data,
work_flow: getGraphData(), work_flow: getGraphData(),
} }
DebugRef.value?.open(graphData, id) DebugRef.value?.open(graphData)
} catch (e: any) { } catch (e: any) {
MsgError(e.toString()) MsgError(e.toString())
} }
@ -471,7 +474,7 @@ const go = () => {
const get_resource_management_route = () => { const get_resource_management_route = () => {
return `/knowledge/${id}/${folderId}/4/document` return `/knowledge/${id}/${folderId}/4/document`
// return `/system/resource-management/knowledge` // return `/system/resource-management/knowledge` resource-management
} }
const get_route = () => { const get_route = () => {