Skip to content

Commit c4dd09c

Browse files
authored
feat: Knowledge Base Workflow Execution Record (#4435)
1 parent 0db2622 commit c4dd09c

File tree

6 files changed

+188
-21
lines changed

6 files changed

+188
-21
lines changed

apps/knowledge/serializers/knowledge_workflow.py

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from application.flow.knowledge_workflow_manage import KnowledgeWorkflowManage
1616
from application.flow.step_node import get_node
1717
from application.serializers.application import get_mcp_tools
18+
from common.db.search import page_search
1819
from common.exception.app_exception import AppApiException
1920
from common.utils.rsa_util import rsa_long_decrypt
2021
from common.utils.tool_code import ToolExecutor
@@ -41,16 +42,46 @@ class KnowledgeWorkflowActionRequestSerializer(serializers.Serializer):
4142
knowledge_base = serializers.DictField(required=True, label=_('knowledge base data'))
4243

4344

45+
class KnowledgeWorkflowActionListQuerySerializer(serializers.Serializer):
46+
user_name = serializers.CharField(required=False, label=_('Name'), allow_blank=True, allow_null=True)
47+
48+
4449
class KnowledgeWorkflowActionSerializer(serializers.Serializer):
4550
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
4651
knowledge_id = serializers.UUIDField(required=True, label=_('knowledge id'))
4752

48-
def action(self, instance: Dict, with_valid=True):
53+
def get_query_set(self, instance: Dict):
54+
query_set = QuerySet(KnowledgeAction).filter(knowledge_id=self.data.get('knowledge_id'))
55+
if instance.get("user_name"):
56+
query_set = query_set.filter(meta__user_name__icontains=instance.get('user_name'))
57+
return query_set.order_by('-create_time')
58+
59+
def list(self, instance: Dict, is_valid=True):
60+
if is_valid:
61+
self.is_valid(raise_exception=True)
62+
KnowledgeWorkflowActionListQuerySerializer(data=instance).is_valid(raise_exception=True)
63+
return [{'id': a.id, 'knowledge_id': a.knowledge_id, 'state': a.state,
64+
'details': a.details, 'meta': a.meta, 'run_time': a.run_time} for a in self.get_query_set(instance)]
65+
66+
def page(self, current_page, page_size, instance: Dict, is_valid=True):
67+
if is_valid:
68+
self.is_valid(raise_exception=True)
69+
KnowledgeWorkflowActionListQuerySerializer(data=instance).is_valid(raise_exception=True)
70+
return page_search(current_page, page_size, self.get_query_set(instance),
71+
lambda a: {'id': a.id, 'knowledge_id': a.knowledge_id, 'state': a.state,
72+
'details': a.details, 'meta': a.meta, 'run_time': a.run_time})
73+
74+
def action(self, instance: Dict, user, with_valid=True):
4975
if with_valid:
5076
self.is_valid(raise_exception=True)
5177
knowledge_workflow = QuerySet(KnowledgeWorkflow).filter(knowledge_id=self.data.get("knowledge_id")).first()
5278
knowledge_action_id = uuid.uuid7()
53-
KnowledgeAction(id=knowledge_action_id, knowledge_id=self.data.get("knowledge_id"), state=State.STARTED).save()
79+
meta = {'user_id': str(user.id),
80+
'user_name': user.username}
81+
KnowledgeAction(id=knowledge_action_id,
82+
knowledge_id=self.data.get("knowledge_id"),
83+
state=State.STARTED,
84+
meta=meta).save()
5485
work_flow_manage = KnowledgeWorkflowManage(
5586
Workflow.new_instance(knowledge_workflow.work_flow, WorkflowMode.KNOWLEDGE),
5687
{'knowledge_id': self.data.get("knowledge_id"), 'knowledge_action_id': knowledge_action_id, 'stream': True,
@@ -59,9 +90,9 @@ def action(self, instance: Dict, with_valid=True):
5990
KnowledgeWorkflowPostHandler(None, knowledge_action_id))
6091
work_flow_manage.run()
6192
return {'id': knowledge_action_id, 'knowledge_id': self.data.get("knowledge_id"), 'state': State.STARTED,
62-
'details': {}}
93+
'details': {}, 'meta': meta}
6394

64-
def upload_document(self, instance: Dict, with_valid=True):
95+
def upload_document(self, instance: Dict, user, with_valid=True):
6596
if with_valid:
6697
self.is_valid(raise_exception=True)
6798
knowledge_workflow = QuerySet(KnowledgeWorkflow).filter(knowledge_id=self.data.get("knowledge_id")).first()
@@ -71,7 +102,10 @@ def upload_document(self, instance: Dict, with_valid=True):
71102
knowledge_id=self.data.get("knowledge_id")).order_by(
72103
'-create_time')[0:1].first()
73104
knowledge_action_id = uuid.uuid7()
74-
KnowledgeAction(id=knowledge_action_id, knowledge_id=self.data.get("knowledge_id"), state=State.STARTED).save()
105+
meta = {'user_id': str(user.id),
106+
'user_name': user.username}
107+
KnowledgeAction(id=knowledge_action_id, knowledge_id=self.data.get("knowledge_id"), state=State.STARTED,
108+
meta=meta).save()
75109
work_flow_manage = KnowledgeWorkflowManage(
76110
Workflow.new_instance(knowledge_workflow_version.work_flow, WorkflowMode.KNOWLEDGE),
77111
{'knowledge_id': self.data.get("knowledge_id"), 'knowledge_action_id': knowledge_action_id, 'stream': True,
@@ -80,7 +114,7 @@ def upload_document(self, instance: Dict, with_valid=True):
80114
KnowledgeWorkflowPostHandler(None, knowledge_action_id))
81115
work_flow_manage.run()
82116
return {'id': knowledge_action_id, 'knowledge_id': self.data.get("knowledge_id"), 'state': State.STARTED,
83-
'details': {}}
117+
'details': {}, 'meta': meta}
84118

85119
class Operate(serializers.Serializer):
86120
workspace_id = serializers.CharField(required=True, label=_('workspace id'))
@@ -94,7 +128,8 @@ def one(self, is_valid=True):
94128
knowledge_action = QuerySet(KnowledgeAction).filter(id=knowledge_action_id).first()
95129
return {'id': knowledge_action_id, 'knowledge_id': knowledge_action.knowledge_id,
96130
'state': knowledge_action.state,
97-
'details': knowledge_action.details}
131+
'details': knowledge_action.details,
132+
'meta': knowledge_action.meta}
98133

99134

100135
class KnowledgeWorkflowSerializer(serializers.Serializer):

apps/knowledge/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
path('workspace/<str:workspace_id>/knowledge/<str:knowledge_id>/datasource/<str:type>/<str:id>/<str:function_name>', views.KnowledgeDatasourceView.as_view()),
7474
path('workspace/<str:workspace_id>/knowledge/<str:knowledge_id>/publish', views.KnowledgeWorkflowView.Publish.as_view()),
7575
path('workspace/<str:workspace_id>/knowledge/<str:knowledge_id>/debug', views.KnowledgeWorkflowActionView.as_view()),
76+
path('workspace/<str:workspace_id>/knowledge/<str:knowledge_id>/action/<int:current_page>/<int:page_size>', views.KnowledgeWorkflowActionView.Page.as_view()),
7677
path('workspace/<str:workspace_id>/knowledge/<str:knowledge_id>/upload_document', views.KnowledgeWorkflowUploadDocumentView.as_view()),
7778
path('workspace/<str:workspace_id>/knowledge/<str:knowledge_id>/action/<str:knowledge_action_id>', views.KnowledgeWorkflowActionView.Operate.as_view()),
7879
path('workspace/<str:workspace_id>/knowledge/<str:knowledge_id>/mcp_tools', views.McpServers.as_view()),

apps/knowledge/views/knowledge_workflow.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,15 @@ class KnowledgeWorkflowUploadDocumentView(APIView):
7878
)
7979
def post(self, request: Request, workspace_id: str, knowledge_id: str):
8080
return result.success(KnowledgeWorkflowActionSerializer(
81-
data={'workspace_id': workspace_id, 'knowledge_id': knowledge_id}).upload_document(request.data, True))
81+
data={'workspace_id': workspace_id, 'knowledge_id': knowledge_id}).upload_document(request.data,
82+
request.user, True))
8283

8384

8485
class KnowledgeWorkflowActionView(APIView):
8586
authentication_classes = [TokenAuth]
8687

8788
@extend_schema(
88-
methods=['GET'],
89+
methods=['POST'],
8990
description=_('Knowledge workflow debug'),
9091
summary=_('Knowledge workflow debug'),
9192
operation_id=_('Knowledge workflow debug'), # type: ignore
@@ -106,7 +107,35 @@ class KnowledgeWorkflowActionView(APIView):
106107
)
107108
def post(self, request: Request, workspace_id: str, knowledge_id: str):
108109
return result.success(KnowledgeWorkflowActionSerializer(
109-
data={'workspace_id': workspace_id, 'knowledge_id': knowledge_id}).action(request.data, True))
110+
data={'workspace_id': workspace_id, 'knowledge_id': knowledge_id}).action(request.data, request.user, True))
111+
112+
class Page(APIView):
113+
authentication_classes = [TokenAuth]
114+
115+
@extend_schema(
116+
methods=['GET'],
117+
description=_('Page Knowledge workflow action'),
118+
summary=_('Page Knowledge workflow action'),
119+
operation_id=_('Page Knowledge workflow action'), # type: ignore
120+
parameters=KnowledgeWorkflowActionApi.get_parameters(),
121+
request=KnowledgeWorkflowActionApi.get_request(),
122+
responses=KnowledgeWorkflowActionApi.get_response(),
123+
tags=[_('Knowledge Base')] # type: ignore
124+
)
125+
@has_permissions(
126+
PermissionConstants.KNOWLEDGE_DOCUMENT_CREATE.get_workspace_knowledge_permission(),
127+
PermissionConstants.KNOWLEDGE_DOCUMENT_CREATE.get_workspace_permission_workspace_manage_role(),
128+
RoleConstants.WORKSPACE_MANAGE.get_workspace_role(),
129+
ViewPermission(
130+
[RoleConstants.USER.get_workspace_role()],
131+
[PermissionConstants.KNOWLEDGE.get_workspace_knowledge_permission()],
132+
CompareConstants.AND
133+
),
134+
)
135+
def get(self, request: Request, workspace_id: str, knowledge_id: str, current_page: int, page_size: int):
136+
return result.success(
137+
KnowledgeWorkflowActionSerializer(data={'workspace_id': workspace_id, 'knowledge_id': knowledge_id})
138+
.page(current_page, page_size, request.data))
110139

111140
class Operate(APIView):
112141
authentication_classes = [TokenAuth]

ui/src/api/knowledge/knowledge.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -382,19 +382,19 @@ const publish: (knowledge_id: string, loading?: Ref<boolean>) => Promise<Result<
382382

383383
/**
384384
* 保存知识库工作流
385-
* @param knowledge_id
386-
* @param data
387-
* @param loading
388-
* @returns
385+
* @param knowledge_id
386+
* @param data
387+
* @param loading
388+
* @returns
389389
*/
390390
const putKnowledgeWorkflow: (
391391
knowledge_id: string,
392392
data: any,
393393
loading?: Ref<boolean>,
394394
) => Promise<Result<any>> = (knowledge_id, data, loading) => {
395-
return put(`${prefix.value}/${knowledge_id}/workflow`, data, undefined, loading)
395+
return put(`${prefix.value}/${knowledge_id}/workflow`, data, undefined, loading)
396396
}
397-
397+
398398
const listKnowledgeVersion: (
399399
knowledge_id: string,
400400
loading?: Ref<boolean>,
@@ -414,7 +414,18 @@ const updateKnowledgeVersion: (
414414
loading,
415415
)
416416
}
417-
417+
const pageWorkflowAction: (
418+
knowledge_id: string,
419+
page: pageRequest,
420+
query: any,
421+
loading?: Ref<boolean>,
422+
) => Promise<Result<any>> = (knowledge_id: string, page, query, loading) => {
423+
return get(
424+
`${prefix.value}/${knowledge_id}/action/${page.current_page}/${page.page_size}`,
425+
query,
426+
loading,
427+
)
428+
}
418429
const getWorkflowAction: (
419430
knowledge_id: string,
420431
knowledge_action_id: string,
@@ -468,4 +479,5 @@ export default {
468479
publish,
469480
putKnowledgeWorkflow,
470481
workflowUpload,
482+
pageWorkflowAction,
471483
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<template>
2+
<el-drawer v-model="drawer" title="执行记录" direction="rtl" size="800px" :before-close="close">
3+
<el-table v-if="active == 'list'" :data="data" style="width: 100%">
4+
<el-table-column prop="meta" label="发起人" width="180">
5+
<template #default="{ row }">
6+
{{ row.meta.user_name }}
7+
</template>
8+
</el-table-column>
9+
<el-table-column prop="sate" label="状态" width="180">
10+
<template #default="{ row }">
11+
{{ row.state }}
12+
</template>
13+
</el-table-column>
14+
<el-table-column prop="run_time" label="运行时间">
15+
<template #default="{ row }">
16+
{{ row.run_time }}
17+
</template>
18+
</el-table-column>
19+
<el-table-column label="操作">
20+
<template #default="{ row }">
21+
<span @click="details(row)">执行详情</span>
22+
</template>
23+
</el-table-column>
24+
</el-table>
25+
<Result
26+
v-if="active == 'details'"
27+
:id="active_action_id"
28+
:knowledge_id="active_knowledge_id"
29+
></Result>
30+
</el-drawer>
31+
</template>
32+
<script setup lang="ts">
33+
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
34+
import { computed, ref, reactive } from 'vue'
35+
import Result from '../action/Result.vue'
36+
import { useRoute, useRouter } from 'vue-router'
37+
const drawer = ref<boolean>(false)
38+
const active_knowledge_id = ref<string>()
39+
const active_action_id = ref<string>()
40+
const active = ref<'list' | 'details'>('list')
41+
const route = useRoute()
42+
const details = (row: any) => {
43+
active_action_id.value = row.id
44+
active.value = 'details'
45+
}
46+
47+
const apiType = computed(() => {
48+
if (route.path.includes('shared')) {
49+
return 'systemShare'
50+
} else if (route.path.includes('resource-management')) {
51+
return 'systemManage'
52+
} else {
53+
return 'workspace'
54+
}
55+
})
56+
const paginationConfig = reactive({
57+
current_page: 1,
58+
page_size: 30,
59+
total: 0,
60+
})
61+
const query = ref<any>({
62+
user_name: '',
63+
})
64+
const data = ref<Array<any>>([])
65+
const page = () => {
66+
loadSharedApi({ type: 'knowledge', systemType: apiType.value })
67+
.pageWorkflowAction(active_knowledge_id.value, paginationConfig, query)
68+
.then((ok: any) => {
69+
paginationConfig.total = ok.data?.total
70+
data.value = ok.data.records
71+
})
72+
}
73+
const open = (knowledge_id: string) => {
74+
drawer.value = true
75+
active_knowledge_id.value = knowledge_id
76+
page()
77+
}
78+
const close = () => {
79+
drawer.value = false
80+
}
81+
defineExpose({ open, close })
82+
</script>
83+
<style lang="scss" scoped></style>

ui/src/views/knowledge-workflow/index.vue

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@
3434
<AppIcon iconName="app-debug-outlined" class="mr-4"></AppIcon>
3535
{{ $t('common.debug') }}
3636
</el-button>
37-
<el-button v-if="permissionPrecise.workflow_edit(id)"
38-
@click="saveknowledge(true)">
37+
<el-button v-if="permissionPrecise.workflow_edit(id)" @click="saveknowledge(true)">
3938
<AppIcon iconName="app-save-outlined" class="mr-4"></AppIcon>
4039
{{ $t('common.save') }}
4140
</el-button>
@@ -53,7 +52,10 @@
5352
<AppIcon iconName="app-import-doc" class="color-secondary"></AppIcon>
5453
{{ $t('views.workflow.operation.toImportDoc') }}
5554
</el-dropdown-item>
56-
55+
<el-dropdown-item @click="openListAction">
56+
<AppIcon iconName="app-history-outlined" class="color-secondary"></AppIcon>
57+
执行记录
58+
</el-dropdown-item>
5759
<el-dropdown-item @click="openHistory">
5860
<AppIcon iconName="app-history-outlined" class="color-secondary"></AppIcon>
5961
{{ $t('views.workflow.setting.releaseHistory') }}
@@ -127,6 +129,7 @@
127129
</div>
128130
</el-collapse-transition>
129131
<DebugVue ref="DebugRef"></DebugVue>
132+
<ListAction ref="ListActionRef"></ListAction>
130133
<!-- 发布历史 -->
131134
<PublishHistory
132135
v-if="showHistory"
@@ -142,6 +145,7 @@ import { useRouter, useRoute } from 'vue-router'
142145
import type { Action } from 'element-plus'
143146
import Workflow from '@/workflow/index.vue'
144147
import DropdownMenu from '@/components/workflow-dropdown-menu/index.vue'
148+
import ListAction from '@/views/knowledge-workflow/component/list-action/index.vue'
145149
import PublishHistory from '@/views/knowledge-workflow/component/PublishHistory.vue'
146150
import { isAppIcon, resetUrl } from '@/utils/common'
147151
import { MsgSuccess, MsgError, MsgConfirm } from '@/utils/message'
@@ -190,7 +194,7 @@ const isDefaultTheme = computed(() => {
190194
return theme.isDefaultTheme()
191195
})
192196
const DebugRef = ref<InstanceType<typeof DebugVue>>()
193-
197+
const ListActionRef = ref<InstanceType<typeof ListAction>>()
194198
let interval: any
195199
const workflowRef = ref()
196200
const workflowMainRef = ref()
@@ -235,6 +239,9 @@ function back() {
235239
go()
236240
}
237241
}
242+
const openListAction = () => {
243+
ListActionRef.value?.open(id)
244+
}
238245
function clickoutsideHistory() {
239246
if (!disablePublic.value) {
240247
showHistory.value = false

0 commit comments

Comments
 (0)