mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-25 17:22:55 +00:00
Compare commits
6 Commits
4ffdb46b0a
...
4cecf86543
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4cecf86543 | ||
|
|
c362b4ed4e | ||
|
|
c0f63e9e3d | ||
|
|
bd9faa89bd | ||
|
|
c067479643 | ||
|
|
71c63adb0b |
|
|
@ -26,6 +26,7 @@ from application.chat_pipeline.pipeline_manage import PipelineManage
|
|||
from application.chat_pipeline.step.chat_step.i_chat_step import IChatStep, PostResponseHandler
|
||||
from application.flow.tools import Reasoning, mcp_response_generator
|
||||
from application.models import ApplicationChatUserStats, ChatUserType, Application, ApplicationApiKey
|
||||
from common.exception.app_exception import AppApiException
|
||||
from common.utils.logger import maxkb_logger
|
||||
from common.utils.rsa_util import rsa_long_decrypt
|
||||
from common.utils.tool_code import ToolExecutor
|
||||
|
|
@ -273,7 +274,10 @@ class BaseChatStep(IChatStep):
|
|||
if app_key is not None:
|
||||
api_key = app_key.secret_key
|
||||
else:
|
||||
continue
|
||||
raise AppApiException(
|
||||
500,
|
||||
_('Application Key is required for application tool 【{name}】').format(name=app.name)
|
||||
)
|
||||
executor = ToolExecutor()
|
||||
app_config = executor.get_app_mcp_config(api_key)
|
||||
mcp_servers_config[app.name] = app_config
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ from functools import reduce
|
|||
from typing import List, Dict
|
||||
|
||||
from django.db.models import QuerySet
|
||||
from django.utils.translation import gettext as _
|
||||
from langchain.schema import HumanMessage, SystemMessage
|
||||
from langchain_core.messages import BaseMessage, AIMessage
|
||||
|
||||
|
|
@ -20,6 +21,7 @@ from application.flow.i_step_node import NodeResult, INode
|
|||
from application.flow.step_node.ai_chat_step_node.i_chat_node import IChatNode
|
||||
from application.flow.tools import Reasoning, mcp_response_generator
|
||||
from application.models import Application, ApplicationApiKey
|
||||
from common.exception.app_exception import AppApiException
|
||||
from common.utils.rsa_util import rsa_long_decrypt
|
||||
from common.utils.tool_code import ToolExecutor
|
||||
from models_provider.models import Model
|
||||
|
|
@ -259,7 +261,10 @@ class BaseChatNode(IChatNode):
|
|||
if app_key is not None:
|
||||
api_key = app_key.secret_key
|
||||
else:
|
||||
continue
|
||||
raise AppApiException(
|
||||
500,
|
||||
_('Application Key is required for application tool 【{name}】').format(name=app.name)
|
||||
)
|
||||
executor = ToolExecutor()
|
||||
app_config = executor.get_app_mcp_config(api_key)
|
||||
mcp_servers_config[app.name] = app_config
|
||||
|
|
|
|||
|
|
@ -558,7 +558,7 @@ class PermissionConstants(Enum):
|
|||
)
|
||||
TOOL_FOLDER_READ = Permission(
|
||||
group=Group.TOOL_FOLDER, operate=Operate.READ, role_list=[RoleConstants.ADMIN, RoleConstants.USER],
|
||||
parent_group=[WorkspaceGroup.TOOL, UserGroup.TOOL],
|
||||
parent_group=[UserGroup.TOOL],
|
||||
resource_permission_group_list=[ResourcePermissionConst.TOOL_VIEW]
|
||||
)
|
||||
TOOL_FOLDER_CREATE = Permission(
|
||||
|
|
@ -629,7 +629,7 @@ class PermissionConstants(Enum):
|
|||
KNOWLEDGE_FOLDER_READ = Permission(
|
||||
group=Group.KNOWLEDGE_FOLDER, operate=Operate.READ, role_list=[RoleConstants.ADMIN, RoleConstants.USER],
|
||||
resource_permission_group_list=[ResourcePermissionConst.KNOWLEDGE_VIEW],
|
||||
parent_group = [WorkspaceGroup.KNOWLEDGE, UserGroup.KNOWLEDGE]
|
||||
parent_group = [UserGroup.KNOWLEDGE]
|
||||
)
|
||||
KNOWLEDGE_FOLDER_CREATE = Permission(
|
||||
group=Group.KNOWLEDGE_FOLDER, operate=Operate.CREATE, role_list=[RoleConstants.ADMIN, RoleConstants.USER],
|
||||
|
|
@ -961,7 +961,7 @@ class PermissionConstants(Enum):
|
|||
)
|
||||
APPLICATION_FOLDER_READ = Permission(group=Group.APPLICATION_FOLDER, operate=Operate.READ,
|
||||
role_list=[RoleConstants.ADMIN, RoleConstants.USER],
|
||||
parent_group=[WorkspaceGroup.APPLICATION, UserGroup.APPLICATION],
|
||||
parent_group=[UserGroup.APPLICATION],
|
||||
resource_permission_group_list=[ResourcePermissionConst.APPLICATION_VIEW]
|
||||
)
|
||||
APPLICATION_FOLDER_CREATE = Permission(group=Group.APPLICATION_FOLDER, operate=Operate.CREATE,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ from rest_framework import serializers
|
|||
from application.models.application import Application, ApplicationFolder
|
||||
from application.serializers.application import ApplicationOperateSerializer
|
||||
from application.serializers.application_folder import ApplicationFolderTreeSerializer
|
||||
from common.constants.permission_constants import Group, ResourcePermission, ResourcePermissionRole
|
||||
from common.constants.permission_constants import Group, ResourcePermission, ResourcePermissionRole, RoleConstants
|
||||
from common.database_model_manage.database_model_manage import DatabaseModelManage
|
||||
from common.exception.app_exception import AppApiException
|
||||
from folders.api.folder import FolderCreateRequest
|
||||
from knowledge.models import KnowledgeFolder, Knowledge
|
||||
|
|
@ -300,30 +301,52 @@ class FolderTreeSerializer(serializers.Serializer):
|
|||
return True # 需要重建
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _having_read_permission_by_role(user_id: str, workspace_id: str, source: str):
|
||||
workspace_user_role_mapping_model = DatabaseModelManage.get_model("workspace_user_role_mapping")
|
||||
role_permission_mapping_model = DatabaseModelManage.get_model("role_permission_mapping_model")
|
||||
is_x_pack_ee = workspace_user_role_mapping_model is not None and role_permission_mapping_model is not None
|
||||
if is_x_pack_ee:
|
||||
return QuerySet(workspace_user_role_mapping_model).select_related('role', 'user').filter(
|
||||
workspace_id=workspace_id, user_id=user_id,
|
||||
role__type=RoleConstants.USER.value.__str__(),
|
||||
role__rolepermission__permission_id=f"{source}_FOLDER:READ"
|
||||
).exists()
|
||||
|
||||
return False
|
||||
|
||||
def get_folder_tree(self,
|
||||
current_user, name=None):
|
||||
self.is_valid(raise_exception=True)
|
||||
Folder = get_folder_type(self.data.get('source')) # noqa
|
||||
user_id = current_user.id
|
||||
workspace_id = self.data.get('workspace_id')
|
||||
source = self.data.get('source')
|
||||
|
||||
Folder = get_folder_type(source) # noqa
|
||||
|
||||
# 检查特定工作空间的树结构完整性
|
||||
workspace_folders = Folder.objects.filter(workspace_id=self.data.get('workspace_id'))
|
||||
|
||||
workspace_folders = Folder.objects.filter(workspace_id=workspace_id)
|
||||
# 如果发现数据不一致,重建整个表(这是 MPTT 的限制)
|
||||
if self._check_tree_integrity(workspace_folders):
|
||||
Folder.objects.rebuild()
|
||||
|
||||
workspace_manage = is_workspace_manage(current_user.id, self.data.get('workspace_id'))
|
||||
workspace_manage = is_workspace_manage(user_id, workspace_id)
|
||||
|
||||
base_q = Q(workspace_id=self.data.get('workspace_id'))
|
||||
base_q = Q(workspace_id=workspace_id)
|
||||
|
||||
if name is not None:
|
||||
base_q &= Q(name__contains=name)
|
||||
if not workspace_manage:
|
||||
having_read_permission_by_role = self._having_read_permission_by_role(user_id, workspace_id, source)
|
||||
permission_condition = ['VIEW']
|
||||
if having_read_permission_by_role:
|
||||
permission_condition = ['VIEW', 'ROLE']
|
||||
|
||||
base_q &= (Q(id__in=WorkspaceUserResourcePermission.objects.filter(user_id=current_user.id,
|
||||
auth_target_type=self.data.get('source'),
|
||||
workspace_id=self.data.get(
|
||||
'workspace_id'),
|
||||
permission_list__contains=['VIEW'])
|
||||
permission_list__overlap=permission_condition)
|
||||
.values_list(
|
||||
'target', flat=True)) | Q(id=self.data.get('workspace_id')))
|
||||
|
||||
|
|
@ -332,4 +355,5 @@ class FolderTreeSerializer(serializers.Serializer):
|
|||
TreeSerializer = get_folder_tree_serializer(self.data.get('source')) # noqa
|
||||
serializer = TreeSerializer(nodes, many=True)
|
||||
|
||||
return [d for d in serializer.data if d.get('id') == d.get('workspace_id')] if name is None else serializer.data # 这是可序列化的字典
|
||||
return [d for d in serializer.data if
|
||||
d.get('id') == d.get('workspace_id')] if name is None else serializer.data # 这是可序列化的字典
|
||||
|
|
|
|||
|
|
@ -120,16 +120,16 @@ class WorkspaceResourceUserPermissionView(APIView):
|
|||
resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}:ROLE/WORKSPACE_MANAGE"),
|
||||
lambda r, kwargs: Permission(group=Group(kwargs.get('resource')),
|
||||
operate=Operate.AUTH,
|
||||
resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource')}/{kwargs.get('target')}"),
|
||||
resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource').replace('_FOLDER','')}/{kwargs.get('target')}"),
|
||||
ViewPermission([RoleConstants.USER.get_workspace_role()],
|
||||
[lambda r, kwargs: Permission(group=Group(kwargs.get('resource')),
|
||||
operate=Operate.SELF,
|
||||
resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource')}/{kwargs.get('target')}")],
|
||||
resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource').replace('_FOLDER','')}/{kwargs.get('target')}")],
|
||||
CompareConstants.AND),
|
||||
RoleConstants.WORKSPACE_MANAGE.get_workspace_role())
|
||||
def get(self, request: Request, workspace_id: str, target: str, resource: str):
|
||||
return result.success(ResourceUserPermissionSerializer(
|
||||
data={'workspace_id': workspace_id, "target": target, 'auth_target_type': resource,
|
||||
data={'workspace_id': workspace_id, "target": target, 'auth_target_type': resource.replace('_FOLDER',''),
|
||||
}).list(
|
||||
{'username': request.query_params.get("username"), 'nick_name': request.query_params.get("nick_name"),
|
||||
'permission': request.query_params.getlist("permission[]")
|
||||
|
|
@ -154,16 +154,16 @@ class WorkspaceResourceUserPermissionView(APIView):
|
|||
resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}:ROLE/WORKSPACE_MANAGE"),
|
||||
lambda r, kwargs: Permission(group=Group(kwargs.get('resource')),
|
||||
operate=Operate.AUTH,
|
||||
resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource')}/{kwargs.get('target')}"),
|
||||
resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource').replace('_FOLDER','')}/{kwargs.get('target')}"),
|
||||
ViewPermission([RoleConstants.USER.get_workspace_role()],
|
||||
[lambda r, kwargs: Permission(group=Group(kwargs.get('resource')),
|
||||
operate=Operate.SELF,
|
||||
resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource')}/{kwargs.get('target')}")],
|
||||
resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource').replace('_FOLDER','')}/{kwargs.get('target')}")],
|
||||
CompareConstants.AND),
|
||||
RoleConstants.WORKSPACE_MANAGE.get_workspace_role())
|
||||
def put(self, request: Request, workspace_id: str, target: str, resource: str):
|
||||
return result.success(ResourceUserPermissionSerializer(
|
||||
data={'workspace_id': workspace_id, "target": target, 'auth_target_type': resource, })
|
||||
data={'workspace_id': workspace_id, "target": target, 'auth_target_type': resource.replace('_FOLDER',''), })
|
||||
.edit(instance=request.data, current_user_id=request.user.id))
|
||||
|
||||
class Page(APIView):
|
||||
|
|
@ -184,17 +184,17 @@ class WorkspaceResourceUserPermissionView(APIView):
|
|||
resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}:ROLE/WORKSPACE_MANAGE"),
|
||||
lambda r, kwargs: Permission(group=Group(kwargs.get('resource')),
|
||||
operate=Operate.AUTH,
|
||||
resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource')}/{kwargs.get('target')}"),
|
||||
resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource').replace('_FOLDER','')}/{kwargs.get('target')}"),
|
||||
ViewPermission([RoleConstants.USER.get_workspace_role()],
|
||||
[lambda r, kwargs: Permission(group=Group(kwargs.get('resource')),
|
||||
operate=Operate.SELF,
|
||||
resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource')}/{kwargs.get('target')}")],
|
||||
resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource').replace('_FOLDER','')}/{kwargs.get('target')}")],
|
||||
CompareConstants.AND),
|
||||
RoleConstants.WORKSPACE_MANAGE.get_workspace_role())
|
||||
def get(self, request: Request, workspace_id: str, target: str, resource: str, current_page: int,
|
||||
page_size: int):
|
||||
return result.success(ResourceUserPermissionSerializer(
|
||||
data={'workspace_id': workspace_id, "target": target, 'auth_target_type': resource, }
|
||||
data={'workspace_id': workspace_id, "target": target, 'auth_target_type': resource.replace('_FOLDER',''), }
|
||||
).page({'username': request.query_params.get("username"),
|
||||
'role': request.query_params.get("role"),
|
||||
'nick_name': request.query_params.get("nick_name"),
|
||||
|
|
|
|||
|
|
@ -219,6 +219,8 @@ function markdownToPlainText(md: string) {
|
|||
.replace(/`(.*?)`/g, '$1')
|
||||
// 移除代码块 ```code```
|
||||
.replace(/```[\s\S]*?```/g, '')
|
||||
// 移除video标签
|
||||
.replace(/<video>[\s\S]*?<\/video>/g, '')
|
||||
// 移除html标签
|
||||
.replace(/<[^>]+>/g, '')
|
||||
// 移除多余的换行符
|
||||
|
|
|
|||
|
|
@ -208,4 +208,25 @@ export default {
|
|||
])
|
||||
},
|
||||
},
|
||||
'app-template-center': {
|
||||
iconReader: () => {
|
||||
return h('i', [
|
||||
h(
|
||||
'svg',
|
||||
{
|
||||
style: { height: '100%', width: '100%' },
|
||||
viewBox: '0 0 1024 1024',
|
||||
version: '1.1',
|
||||
xmlns: 'http://www.w3.org/2000/svg',
|
||||
},
|
||||
[
|
||||
h('path', {
|
||||
d: 'M213.333333 128h469.333334v107.52a21.333333 21.333333 0 0 0 21.333333 21.333333H810.666667V896H213.333333V128z m515.626667-85.333333H170.666667a42.666667 42.666667 0 0 0-42.666667 42.666666v853.333334a42.666667 42.666667 0 0 0 42.666667 42.666666h682.666666a42.666667 42.666667 0 0 0 42.666667-42.666666V209.749333a42.666667 42.666667 0 0 0-12.501333-30.208l-124.330667-124.373333A42.666667 42.666667 0 0 0 729.002667 42.666667zM320 341.333333a21.333333 21.333333 0 0 0-21.333333 21.333334v42.666666a21.333333 21.333333 0 0 0 21.333333 21.333334h384a21.333333 21.333333 0 0 0 21.333333-21.333334v-42.666666a21.333333 21.333333 0 0 0-21.333333-21.333334h-384z m149.333333 192a21.333333 21.333333 0 0 1 21.333334-21.333333h213.333333a21.333333 21.333333 0 0 1 21.333333 21.333333v213.333334a21.333333 21.333333 0 0 1-21.333333 21.333333h-213.333333a21.333333 21.333333 0 0 1-21.333334-21.333333v-213.333334zM320 512a21.333333 21.333333 0 0 0-21.333333 21.333333v213.333334a21.333333 21.333333 0 0 0 21.333333 21.333333h42.666667a21.333333 21.333333 0 0 0 21.333333-21.333333v-213.333334a21.333333 21.333333 0 0 0-21.333333-21.333333h-42.666667z',
|
||||
fill: 'currentColor',
|
||||
}),
|
||||
],
|
||||
),
|
||||
])
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -251,6 +251,48 @@ export const iconMap: any = {
|
|||
])
|
||||
},
|
||||
},
|
||||
'app-download': {
|
||||
iconReader: () => {
|
||||
return h('i', [
|
||||
h(
|
||||
'svg',
|
||||
{
|
||||
style: { height: '100%', width: '100%' },
|
||||
viewBox: '0 0 16 16',
|
||||
version: '1.1',
|
||||
xmlns: 'http://www.w3.org/2000/svg',
|
||||
},
|
||||
[
|
||||
h('path', {
|
||||
d: 'M14 12.3333V14C14 14.3681 13.7015 14.6666 13.3333 14.6666H2.66667C2.29848 14.6666 2 14.3681 2 14V12.3333C2 12.1492 2.14924 12 2.33333 12H3C3.18409 12 3.33333 12.1492 3.33333 12.3333V13.3333H12.6667V12.3333C12.6667 12.1492 12.8159 12 13 12H13.6667C13.8508 12 14 12.1492 14 12.3333ZM8.66667 9.3571L10.6736 7.35013C10.8038 7.21995 11.0149 7.21995 11.1451 7.35013L11.6165 7.82153C11.7466 7.9517 11.7466 8.16276 11.6165 8.29293L8.31663 11.5928C8.25154 11.6579 8.16623 11.6904 8.08092 11.6904C7.99562 11.6904 7.91031 11.6579 7.84522 11.5928L4.54539 8.29293C4.41521 8.16276 4.41521 7.9517 4.54539 7.82153L5.01679 7.35013C5.14697 7.21995 5.35802 7.21995 5.4882 7.35013L7.33334 9.19526V1.99996C7.33334 1.81586 7.48257 1.66663 7.66667 1.66663H8.33334C8.51743 1.66663 8.66667 1.81586 8.66667 1.99996V9.3571Z',
|
||||
fill: 'currentColor',
|
||||
}),
|
||||
],
|
||||
),
|
||||
])
|
||||
},
|
||||
},
|
||||
'app-upload': {
|
||||
iconReader: () => {
|
||||
return h('i', [
|
||||
h(
|
||||
'svg',
|
||||
{
|
||||
style: { height: '100%', width: '100%' },
|
||||
viewBox: '0 0 1024 1024',
|
||||
version: '1.1',
|
||||
xmlns: 'http://www.w3.org/2000/svg',
|
||||
},
|
||||
[
|
||||
h('path', {
|
||||
d: 'M896 789.333333V896a42.666667 42.666667 0 0 1-42.666667 42.666667H170.666667a42.666667 42.666667 0 0 1-42.666667-42.666667v-106.666667a21.333333 21.333333 0 0 1 21.333333-21.333333h42.666667a21.333333 21.333333 0 0 1 21.333333 21.333333V853.333333h597.333334v-64a21.333333 21.333333 0 0 1 21.333333-21.333333h42.666667a21.333333 21.333333 0 0 1 21.333333 21.333333z m-341.333333-512l128.426666 128.426667a21.333333 21.333333 0 0 0 30.208 0l30.165334-30.165333a21.333333 21.333333 0 0 0 0-30.165334l-211.2-211.2a21.248 21.248 0 0 0-30.165334 0l-211.2 211.2a21.333333 21.333333 0 0 0 0 30.165334l30.165334 30.165333a21.333333 21.333333 0 0 0 30.165333 0L469.333333 287.701333v460.501334a21.333333 21.333333 0 0 0 21.333334 21.333333h42.666666a21.333333 21.333333 0 0 0 21.333334-21.333333V277.333333z',
|
||||
fill: 'currentColor',
|
||||
}),
|
||||
],
|
||||
),
|
||||
])
|
||||
},
|
||||
},
|
||||
'app-404': {
|
||||
iconReader: () => {
|
||||
return h('i', [
|
||||
|
|
|
|||
|
|
@ -141,4 +141,5 @@ export default {
|
|||
prev: 'Previous',
|
||||
next: 'Next',
|
||||
},
|
||||
use: 'Use',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ export default {
|
|||
debug: 'Run',
|
||||
exit: 'Exit',
|
||||
exitSave: 'Save & Exit',
|
||||
templateCenter: 'Template Center',
|
||||
},
|
||||
tip: {
|
||||
noData: 'No related results found',
|
||||
|
|
|
|||
|
|
@ -141,4 +141,5 @@ export default {
|
|||
prev: '上一步',
|
||||
next: '下一步',
|
||||
},
|
||||
use: '使用',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ export default {
|
|||
copyParam: '复制参数',
|
||||
exit: '直接退出',
|
||||
exitSave: '保存并退出',
|
||||
templateCenter: '模板中心',
|
||||
},
|
||||
tip: {
|
||||
noData: '没有找到相关结果',
|
||||
|
|
|
|||
|
|
@ -140,4 +140,5 @@ export default {
|
|||
prev: '上一步',
|
||||
next: '下一步',
|
||||
},
|
||||
use: '使用',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ export default {
|
|||
copyParam: '複製參數',
|
||||
exit: '直接退出',
|
||||
exitSave: '保存並退出',
|
||||
templateCenter: '模板中心',
|
||||
},
|
||||
tip: {
|
||||
noData: '沒有找到相關結果',
|
||||
|
|
|
|||
|
|
@ -524,9 +524,7 @@
|
|||
@click.stop="downloadDocument(row)"
|
||||
v-if="permissionPrecise.doc_download(id)"
|
||||
>
|
||||
<el-icon class="color-secondary">
|
||||
<Download />
|
||||
</el-icon>
|
||||
<AppIcon iconName="app-download" class="color-secondary" />
|
||||
{{ $t('views.document.setting.download') }}
|
||||
</el-dropdown-item>
|
||||
<el-upload
|
||||
|
|
@ -539,9 +537,7 @@
|
|||
:on-change="(file: any, fileList: any) => replaceDocument(file, row)"
|
||||
>
|
||||
<el-dropdown-item>
|
||||
<el-icon class="color-secondary">
|
||||
<Upload />
|
||||
</el-icon>
|
||||
<AppIcon iconName="app-upload" class="color-secondary" />
|
||||
{{ $t('views.document.setting.replace') }}
|
||||
</el-dropdown-item>
|
||||
</el-upload>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,8 @@
|
|||
v-if="permissionPrecise.create()"
|
||||
@click="openTemplateStoreDialog()"
|
||||
>
|
||||
{{ $t('模版中心') }}
|
||||
<AppIcon iconName="app-template-center" class="mr-4" />
|
||||
{{ $t('workflow.setting.templateCenter') }}
|
||||
</el-button>
|
||||
<el-button @click="showPopover = !showPopover">
|
||||
<AppIcon iconName="app-add-outlined" class="mr-4" />
|
||||
|
|
@ -169,7 +170,12 @@
|
|||
v-click-outside="clickoutsideHistory"
|
||||
@refreshVersion="refreshVersion"
|
||||
/>
|
||||
<TemplateStoreDialog ref="templateStoreDialogRef" :api-type="apiType" source="work_flow" @refresh="getDetail"/>
|
||||
<TemplateStoreDialog
|
||||
ref="templateStoreDialogRef"
|
||||
:api-type="apiType"
|
||||
source="work_flow"
|
||||
@refresh="getDetail"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
|
|
@ -183,7 +189,6 @@ import PublishHistory from '@/views/knowledge-workflow/component/PublishHistory.
|
|||
import { isAppIcon, resetUrl } from '@/utils/common'
|
||||
import { MsgSuccess, MsgError, MsgConfirm } from '@/utils/message'
|
||||
import { datetimeFormat } from '@/utils/time'
|
||||
import { mapToUrlParams } from '@/utils/application'
|
||||
import useStore from '@/stores'
|
||||
import { KnowledgeWorkFlowInstance } from '@/workflow/common/validate'
|
||||
import { hasPermission } from '@/utils/permission'
|
||||
|
|
@ -195,7 +200,7 @@ import permissionMap from '@/permission'
|
|||
import { WorkflowMode } from '@/enums/application'
|
||||
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
|
||||
import { knowledgeBaseNode } from '@/workflow/common/data'
|
||||
import TemplateStoreDialog from "@/views/knowledge/template-store/TemplateStoreDialog.vue";
|
||||
import TemplateStoreDialog from '@/views/knowledge/template-store/TemplateStoreDialog.vue'
|
||||
provide('getResourceDetail', () => detail)
|
||||
provide('workflowMode', WorkflowMode.Knowledge)
|
||||
provide('loopWorkflowMode', WorkflowMode.KnowledgeLoop)
|
||||
|
|
@ -664,7 +669,6 @@ function openTemplateStoreDialog() {
|
|||
templateStoreDialogRef.value?.open(folderId)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 定时保存
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@
|
|||
v-if="!isShared && permissionPrecise.create()"
|
||||
@click="openTemplateStoreDialog()"
|
||||
>
|
||||
{{ $t('模版中心') }}
|
||||
<AppIcon iconName="app-template-center" class="mr-4" />
|
||||
{{ $t('workflow.setting.templateCenter') }}
|
||||
</el-button>
|
||||
<el-dropdown trigger="click" v-if="!isShared && permissionPrecise.create()">
|
||||
<el-button type="primary" class="ml-8">
|
||||
|
|
@ -337,7 +338,7 @@ import { i18n_name } from '@/utils/common'
|
|||
import { SourceTypeEnum } from '@/enums/common'
|
||||
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
|
||||
import permissionMap from '@/permission'
|
||||
import TemplateStoreDialog from "@/views/knowledge/template-store/TemplateStoreDialog.vue";
|
||||
import TemplateStoreDialog from '@/views/knowledge/template-store/TemplateStoreDialog.vue'
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const { folder, user, knowledge } = useStore()
|
||||
|
|
|
|||
|
|
@ -7,41 +7,34 @@
|
|||
<Back />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
<h4>详情</h4>
|
||||
<h4>{{ $t('common.detail') }}</h4>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div>
|
||||
<div class="card-header">
|
||||
<div class="flex-between">
|
||||
<div class="border-b">
|
||||
<div class="flex-between mb-24">
|
||||
<div class="title flex align-center">
|
||||
<el-avatar
|
||||
v-if="isAppIcon(toolDetail?.icon)"
|
||||
shape="square"
|
||||
:size="64"
|
||||
style="background: none"
|
||||
class="mr-8"
|
||||
>
|
||||
<img :src="toolDetail?.icon" alt="" />
|
||||
<el-avatar shape="square" :size="64" style="background: none">
|
||||
<img src="@/assets/knowledge/icon_basic_template.svg" alt="" />
|
||||
</el-avatar>
|
||||
<el-avatar
|
||||
v-else-if="toolDetail?.name"
|
||||
:name="toolDetail?.name"
|
||||
pinyinColor
|
||||
shape="square"
|
||||
:size="64"
|
||||
class="mr-8"
|
||||
/>
|
||||
<div class="ml-16">
|
||||
<h3 class="mb-8">{{ toolDetail.name }}</h3>
|
||||
<el-text type="info" v-if="toolDetail?.desc">
|
||||
{{ toolDetail.desc }}
|
||||
</el-text>
|
||||
<span
|
||||
class="color-secondary flex align-center mt-8"
|
||||
v-if="toolDetail?.downloads != undefined"
|
||||
>
|
||||
<AppIcon iconName="app-download" class="mr-4" />
|
||||
<span> {{ numberFormat(toolDetail.downloads || 0) }} </span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div @click.stop>
|
||||
<el-button type="primary" @click="addInternalTool(toolDetail)">
|
||||
{{ $t('common.add') }}
|
||||
{{ $t('common.use') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,53 +1,38 @@
|
|||
<template>
|
||||
<CardBox :title="props.tool.name" :description="props.tool.desc" class="cursor tool-card">
|
||||
<template #icon>
|
||||
<el-avatar
|
||||
v-if="isAppIcon(props.tool?.icon)"
|
||||
shape="square"
|
||||
:size="32"
|
||||
style="background: none"
|
||||
>
|
||||
<img :src="resetUrl(props.tool?.icon)" alt=""/>
|
||||
<el-avatar shape="square" :size="32" style="background: none">
|
||||
<img src="@/assets/knowledge/icon_basic_template.svg" alt="" />
|
||||
</el-avatar>
|
||||
<el-avatar
|
||||
v-else-if="props.tool?.name"
|
||||
:name="props.tool?.name"
|
||||
pinyinColor
|
||||
shape="square"
|
||||
:size="32"
|
||||
/>
|
||||
</template>
|
||||
<template #title>
|
||||
<div class="flex align-center">
|
||||
<span :title="props.tool?.name" class="ellipsis"> {{ props.tool?.name }}</span>
|
||||
<el-tag v-if="props.tool?.version" class="ml-4" type="info" effect="plain">
|
||||
{{ props.tool?.version }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<span :title="props.tool?.name" class="ellipsis"> {{ props.tool?.name }}</span>
|
||||
</template>
|
||||
<template #tag>
|
||||
<!-- <template #tag>
|
||||
<el-tag type="info" v-if="props.tool?.label === 'knowledge_template'" class="info-tag">
|
||||
{{ $t('知识库') }}
|
||||
</el-tag>
|
||||
<el-tag type="info" class="info-tag" v-else>
|
||||
{{ $t('views.tool.title') }}
|
||||
</el-tag>
|
||||
</template>
|
||||
<template #subTitle>
|
||||
</template> -->
|
||||
<!-- <template #subTitle>
|
||||
<el-text class="color-secondary lighter" size="small">
|
||||
{{ getSubTitle(props.tool) }}
|
||||
</el-text>
|
||||
</template>
|
||||
</template> -->
|
||||
<template #footer>
|
||||
<span class="card-footer-left color-secondary" v-if="props.tool?.downloads != undefined">
|
||||
{{ `${$t('views.document.upload.download')}: ${numberFormat(props.tool.downloads || 0)} ` }}
|
||||
<span class="card-footer-left color-secondary flex align-center" v-if="props.tool?.downloads != undefined">
|
||||
<AppIcon iconName="app-download" class="mr-4" />
|
||||
<span> {{ numberFormat(props.tool.downloads || 0) }} </span>
|
||||
</span>
|
||||
|
||||
<div class="card-footer-operation mb-8" @click.stop>
|
||||
<el-button @click="emit('handleDetail')">
|
||||
{{ $t('common.detail') }}
|
||||
</el-button>
|
||||
<el-button type="primary" :loading="props.addLoading" @click="emit('handleAdd')">
|
||||
{{ $t('common.add') }}
|
||||
{{ $t('common.use') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
width="1200"
|
||||
width="1000"
|
||||
append-to-body
|
||||
class="tool-store-dialog"
|
||||
align-center
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
<template #header="{ titleId }">
|
||||
<div class="dialog-header flex-between mb-8">
|
||||
<h4 :id="titleId" class="medium w-240 mr-8">
|
||||
{{ $t('模版中心') }}
|
||||
{{ $t('workflow.setting.templateCenter') }}
|
||||
</h4>
|
||||
|
||||
<div class="flex align-center" style="margin-right: 28px">
|
||||
|
|
@ -23,12 +23,12 @@
|
|||
clearable
|
||||
@change="getList"
|
||||
/>
|
||||
<el-divider direction="vertical"/>
|
||||
<el-divider direction="vertical" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<LayoutContainer v-loading="loading" :minLeftWidth="204">
|
||||
<!-- <LayoutContainer v-loading="loading" :minLeftWidth="204">
|
||||
<template #left>
|
||||
<el-anchor
|
||||
direction="vertical"
|
||||
|
|
@ -44,54 +44,54 @@
|
|||
:title="category.title"
|
||||
/>
|
||||
</el-anchor>
|
||||
</template>
|
||||
</template> -->
|
||||
|
||||
<el-scrollbar class="layout-bg" wrap-class="p-16-24 category-scrollbar">
|
||||
<template v-if="filterList === null">
|
||||
<div v-for="category in categories" :key="category.id">
|
||||
<h4
|
||||
<el-scrollbar class="layout-bg" wrap-class="p-16-24 category-scrollbar">
|
||||
<template v-if="filterList === null">
|
||||
<div v-for="category in categories" :key="category.id">
|
||||
<!-- <h4
|
||||
class="title-decoration-1 mb-16 mt-8 color-text-primary"
|
||||
:id="`category-${category.id}`"
|
||||
>
|
||||
{{ category.title }}
|
||||
</h4>
|
||||
<el-row :gutter="16">
|
||||
<el-col v-for="tool in category.tools" :key="tool.id" :span="8" class="mb-16">
|
||||
<TemplateCard
|
||||
:tool="tool"
|
||||
:addLoading="addLoading"
|
||||
:get-sub-title="getSubTitle"
|
||||
@handleAdd="handleOpenAdd(tool)"
|
||||
@handleDetail="handleDetail(tool)"
|
||||
>
|
||||
</TemplateCard>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else>
|
||||
<h4 class="color-text-primary medium mb-16">
|
||||
<span class="color-primary">{{ searchValue }}</span>
|
||||
{{ t('views.tool.toolStore.searchResult', {count: filterList.length}) }}
|
||||
</h4>
|
||||
<el-row :gutter="16" v-if="filterList.length">
|
||||
<el-col v-for="tool in filterList" :key="tool.id" :span="12" class="mb-16">
|
||||
</h4> -->
|
||||
<el-row :gutter="16">
|
||||
<el-col v-for="tool in category.tools" :key="tool.id" :span="8" class="mb-16">
|
||||
<TemplateCard
|
||||
:tool="tool"
|
||||
:addLoading="addLoading"
|
||||
:get-sub-title="getSubTitle"
|
||||
@handleAdd="handleOpenAdd(tool)"
|
||||
@handleDetail="handleDetail(tool)"
|
||||
/>
|
||||
>
|
||||
</TemplateCard>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-empty v-else :description="$t('common.noData')"/>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</LayoutContainer>
|
||||
</template>
|
||||
<div v-else>
|
||||
<!-- <h4 class="color-text-primary medium mb-16">
|
||||
<span class="color-primary">{{ searchValue }}</span>
|
||||
{{ t('views.tool.toolStore.searchResult', { count: filterList.length }) }}
|
||||
</h4> -->
|
||||
<el-row :gutter="16" v-if="filterList.length">
|
||||
<el-col v-for="tool in filterList" :key="tool.id" :span="12" class="mb-16">
|
||||
<TemplateCard
|
||||
:tool="tool"
|
||||
:addLoading="addLoading"
|
||||
:get-sub-title="getSubTitle"
|
||||
@handleAdd="handleOpenAdd(tool)"
|
||||
@handleDetail="handleDetail(tool)"
|
||||
/>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-empty v-else :description="$t('common.noData')" />
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
<!-- </LayoutContainer> -->
|
||||
</el-dialog>
|
||||
<InternalDescDrawer ref="internalDescDrawerRef" @addTool="handleOpenAdd"/>
|
||||
<CreateWorkflowKnowledgeDialog ref="CreateKnowledgeDialogRef"/>
|
||||
<InternalDescDrawer ref="internalDescDrawerRef" @addTool="handleOpenAdd" />
|
||||
<CreateWorkflowKnowledgeDialog ref="CreateKnowledgeDialogRef" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
|
@ -99,18 +99,17 @@ import { ref } from 'vue'
|
|||
import ToolStoreApi from '@/api/tool/store'
|
||||
import { t } from '@/locales'
|
||||
import TemplateCard from './TemplateCard.vue'
|
||||
import { MsgSuccess } from '@/utils/message'
|
||||
import { MsgSuccess, MsgConfirm } from '@/utils/message'
|
||||
import InternalDescDrawer from './InternalDescDrawer.vue'
|
||||
import { loadSharedApi } from '@/utils/dynamics-api/shared-api.ts'
|
||||
import useStore from '@/stores'
|
||||
import CreateWorkflowKnowledgeDialog
|
||||
from "@/views/knowledge/create-component/CreateWorkflowKnowledgeDialog.vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import CreateWorkflowKnowledgeDialog from '@/views/knowledge/create-component/CreateWorkflowKnowledgeDialog.vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
const {user} = useStore()
|
||||
const { user } = useStore()
|
||||
const route = useRoute()
|
||||
const {
|
||||
params: {id},
|
||||
params: { id },
|
||||
/*
|
||||
folderId 可以区分 resource-management shared还是 workspace
|
||||
*/
|
||||
|
|
@ -163,7 +162,7 @@ async function getList() {
|
|||
if (existing) {
|
||||
existing.tools = [...existing.tools, ...category.tools]
|
||||
} else {
|
||||
acc.push({...category})
|
||||
acc.push({ ...category })
|
||||
}
|
||||
return acc
|
||||
}, [] as ToolCategory[])
|
||||
|
|
@ -171,10 +170,9 @@ async function getList() {
|
|||
categories.value = merged.filter((item: any) => item.tools.length > 0)
|
||||
}
|
||||
|
||||
|
||||
async function getStoreToolList() {
|
||||
try {
|
||||
const res = await ToolStoreApi.getStoreKBList({name: searchValue.value}, loading)
|
||||
const res = await ToolStoreApi.getStoreKBList({ name: searchValue.value }, loading)
|
||||
const tags = res.data.additionalProperties.tags
|
||||
const storeTools = res.data.apps
|
||||
let categories = []
|
||||
|
|
@ -213,9 +211,20 @@ const CreateKnowledgeDialogRef = ref()
|
|||
|
||||
function handleOpenAdd(data?: any, isEdit?: boolean) {
|
||||
if (props.source === 'work_flow') {
|
||||
handleStoreAdd(data)
|
||||
MsgConfirm(
|
||||
t('common.tip'),
|
||||
`${t('views.application.tip.confirmUse')} ${data.name} ${t('views.application.tip.overwrite')}?`,
|
||||
{
|
||||
confirmButtonText: t('common.confirm'),
|
||||
cancelButtonText: t('common.cancel'),
|
||||
},
|
||||
)
|
||||
.then(() => {
|
||||
handleStoreAdd(data)
|
||||
})
|
||||
.catch(() => {})
|
||||
} else {
|
||||
CreateKnowledgeDialogRef.value.open({id: folderId.value}, data)
|
||||
CreateKnowledgeDialogRef.value.open({ id: folderId.value }, data)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -223,8 +232,8 @@ const addLoading = ref(false)
|
|||
|
||||
function handleStoreAdd(tool: any) {
|
||||
try {
|
||||
loadSharedApi({type: 'knowledge', systemType: props.apiType})
|
||||
.putKnowledgeWorkflow(id, {work_flow_template: tool})
|
||||
loadSharedApi({ type: 'knowledge', systemType: props.apiType })
|
||||
.putKnowledgeWorkflow(id, { work_flow_template: tool })
|
||||
.then(() => {
|
||||
emit('refresh')
|
||||
MsgSuccess(t('common.addSuccess'))
|
||||
|
|
@ -235,8 +244,7 @@ function handleStoreAdd(tool: any) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
defineExpose({open})
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.tool-store-dialog {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<Back />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
<h4>详情</h4>
|
||||
<h4>{{ $t('common.detail') }}</h4>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -781,14 +781,7 @@ export const menuNodes = [
|
|||
},
|
||||
{
|
||||
label: t('views.knowledge.title'),
|
||||
list: [
|
||||
searchKnowledgeNode,
|
||||
searchDocumentNode,
|
||||
rerankerNode,
|
||||
documentExtractNode,
|
||||
documentSplitNode,
|
||||
knowledgeWriteNode,
|
||||
],
|
||||
list: [searchKnowledgeNode, searchDocumentNode, rerankerNode, documentExtractNode],
|
||||
},
|
||||
{
|
||||
label: t('workflow.nodes.classify.businessLogic'),
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
:title="
|
||||
isEdit
|
||||
? $t('common.param.editParam')
|
||||
: $t('common.param.addParam')
|
||||
"
|
||||
:title="isEdit ? $t('common.param.editParam') : $t('common.param.addParam')"
|
||||
v-model="dialogVisible"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
|
|
@ -59,13 +55,13 @@ const currentRow = computed(() => {
|
|||
input_type: 'TextInput',
|
||||
label: row.label || row.name,
|
||||
default_value: row.default_value,
|
||||
required: row.required != undefined ? row.required : row.is_required
|
||||
required: row.required != undefined ? row.required : row.is_required,
|
||||
}
|
||||
case 'select':
|
||||
if (
|
||||
check_field(
|
||||
['field', 'input_type', 'label', 'required', 'option_list'],
|
||||
currentItem.value
|
||||
currentItem.value,
|
||||
)
|
||||
) {
|
||||
return currentItem.value
|
||||
|
|
@ -81,7 +77,7 @@ const currentRow = computed(() => {
|
|||
? row.option_list
|
||||
: row.optionList.map((o: any) => {
|
||||
return { key: o, value: o }
|
||||
})
|
||||
}),
|
||||
}
|
||||
|
||||
case 'date':
|
||||
|
|
@ -94,9 +90,9 @@ const currentRow = computed(() => {
|
|||
'required',
|
||||
'attrs.format',
|
||||
'attrs.value-format',
|
||||
'attrs.type'
|
||||
'attrs.type',
|
||||
],
|
||||
currentItem.value
|
||||
currentItem.value,
|
||||
)
|
||||
) {
|
||||
return currentItem.value
|
||||
|
|
@ -110,14 +106,19 @@ const currentRow = computed(() => {
|
|||
attrs: {
|
||||
format: 'YYYY-MM-DD HH:mm:ss',
|
||||
'value-format': 'YYYY-MM-DD HH:mm:ss',
|
||||
type: 'datetime'
|
||||
}
|
||||
type: 'datetime',
|
||||
},
|
||||
}
|
||||
default:
|
||||
return currentItem.value
|
||||
}
|
||||
} else {
|
||||
return { input_type: 'TextInput', required: false, attrs: { maxlength: 200, minlength: 0 }, show_default_value: true }
|
||||
return {
|
||||
input_type: 'TextInput',
|
||||
required: false,
|
||||
attrs: { maxlength: 200, minlength: 0 },
|
||||
show_default_value: true,
|
||||
}
|
||||
}
|
||||
})
|
||||
const currentIndex = ref(null)
|
||||
|
|
@ -129,6 +130,9 @@ const inputTypeList = ref([
|
|||
{ label: t('dynamicsForm.input_type_list.RadioCard'), value: 'RadioCardConstructor' },
|
||||
{ label: t('dynamicsForm.input_type_list.DatePicker'), value: 'DatePickerConstructor' },
|
||||
{ label: t('dynamicsForm.input_type_list.SwitchInput'), value: 'SwitchInputConstructor' },
|
||||
{ label: t('dynamicsForm.input_type_list.RadioRow'), value: 'RadioRowConstructor' },
|
||||
{ label: t('dynamicsForm.input_type_list.TextareaInput'), value: 'TextareaInputConstructor' },
|
||||
{ label: t('dynamicsForm.input_type_list.MultiRow'), value: 'MultiRowConstructor' },
|
||||
])
|
||||
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
|
|
|
|||
Loading…
Reference in New Issue