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

View File

@ -33,13 +33,22 @@ const ModelRouter = {
component: () => import('@/views/document/UploadDocument.vue'),
hidden: true,
},
// 上传文档 - 飞书文档
{
path: '/knowledge/import/:folderId/:type',
path: '/knowledge/import/lark/:knowledgeId',
name: 'ImportLarkDocument',
meta: { activeMenu: '/knowledge' },
component: () => import('@/views/document/ImportLarkDocument.vue'),
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',
meta: { activeMenu: '/knowledge' },
component: () => import('@/views/knowledge-workflow/index.vue'),

View File

@ -1,13 +1,13 @@
<template>
<div class="create-knowledge p-12-24">
<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="create-knowledge__main flex" v-loading="loading">
<div class="create-knowledge__component main-calc-height">
<div class="upload-document p-24" style="min-width: 850px">
<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">
<h4 class="title-decoration-1 mb-8">
{{ $t('views.document.feishu.selectDocument') }}
</h4>
@ -127,8 +127,8 @@
</div>
</div>
</el-card>
<div class="create-knowledge__footer text-right border-t">
<el-button @click="router.go(-1)">{{ $t('common.cancel') }}</el-button>
<div class="upload-document__footer text-right border-t">
<el-button @click="back">{{ $t('common.cancel') }}</el-button>
<el-button @click="submit" type="primary" :disabled="disabled">
{{ $t('views.document.buttons.import') }}
@ -147,7 +147,8 @@ import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
const router = useRouter()
const route = useRoute()
const {
query: { id, folder_token }, // idknowledgeIDid folder_tokentoken
params: { knowledgeId },
query: { folder_token }, // idknowledgeIDid folder_tokentoken
} = route
const apiType = computed(() => {
if (route.path.includes('shared')) {
@ -158,7 +159,6 @@ const apiType = computed(() => {
return 'workspace'
}
})
const knowledgeId = id as string
const folderToken = folder_token as string
const loading = ref(false)
@ -250,7 +250,7 @@ function submit() {
.then(() => {
MsgSuccess(t('views.document.tip.importMessage'))
disabled.value = false
router.go(-1)
back()
})
.catch((err: any) => {
console.error('Failed to load tree nodes:', err)
@ -265,37 +265,6 @@ function back() {
router.go(-1)
}
</script>
<style lang="scss" scoped>
.create-knowledge {
&__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 lang="scss">
@use './index.scss';
</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()
})
</script>
<style lang="scss" scoped>
.upload-document {
&__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 lang="scss">
@use './index.scss';
</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"
@click="
router.push({
path: `/knowledge/import/${folderId}/${type}`,
path: `/knowledge/import/lark/${id}`,
query: {
id: id,
folder_token: knowledgeDetail?.meta.folder_token,
},
})
"
>{{ $t('views.document.importDocument') }}
</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
@click="batchRefresh"
:disabled="multipleSelection.length === 0"
@ -132,9 +141,7 @@
clearable
/>
</div>
<el-button @click="openTagDrawer" class="ml-12"
v-if="permissionPrecise.tag_read(id)"
>
<el-button @click="openTagDrawer" class="ml-12" v-if="permissionPrecise.tag_read(id)">
{{ $t('views.document.tag.label') }}
</el-button>
</div>
@ -481,7 +488,8 @@
></AppIcon>
{{ $t('views.document.generateQuestion.title') }}
</el-dropdown-item>
<el-dropdown-item @click="openTagSettingDrawer(row)"
<el-dropdown-item
@click="openTagSettingDrawer(row)"
v-if="permissionPrecise.doc_tag(id)"
>
<AppIcon iconName="app-tag" class="color-secondary"></AppIcon>
@ -605,7 +613,8 @@
<AppIcon iconName="app-sync" class="color-secondary"></AppIcon>
{{ $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)"
>
<AppIcon iconName="app-tag" class="color-secondary"></AppIcon>
@ -783,7 +792,8 @@ const MoreFilledPermission0 = (id: string) => {
permissionPrecise.value.doc_migrate(id) ||
(knowledgeDetail?.value.type === 1 && 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]"
v-model:loading="loading"
:workflow="_workflow"
:knowledge_id="_knowledge_id"
:knowledge_id="id"
:id="action_id"
></component>
</keep-alive>
@ -53,12 +53,18 @@ 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 { WorkflowType } from '@/enums/application'
import { loadSharedApi } from "@/utils/dynamics-api/shared-api.ts";
import { useRoute } from "vue-router";
import { loadSharedApi } from '@/utils/dynamics-api/shared-api.ts'
import { useRoute } from 'vue-router'
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 {
params: { id },
/*
id knowledge_id
*/
} = route as any
const ak = {
data_source: DataSource,
knowledge_base: KnowledgeBase,
@ -80,17 +86,14 @@ const form_data = ref<any>({})
const active = ref<'data_source' | 'knowledge_base' | 'result'>('data_source')
const drawerVisible = ref<boolean>(false)
const _workflow = ref<any>(null)
const _knowledge_id = ref<string>('')
const close = () => {
drawerVisible.value = false
_workflow.value = null
_knowledge_id.value = ''
active.value = 'data_source'
}
const open = (workflow: any, knowledge_id: string) => {
const open = (workflow: any) => {
drawerVisible.value = true
_workflow.value = workflow
_knowledge_id.value = knowledge_id
}
const base_form_list = computed(() => {
@ -115,7 +118,8 @@ const upload = () => {
ActionRef.value.validate().then(() => {
form_data.value[active.value] = ActionRef.value.get_data()
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
active.value = 'result'
})

View File

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

View File

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