refactor: toolStoreDialog

This commit is contained in:
teukkk 2025-06-23 16:47:31 +08:00
parent b971a2c15f
commit b2465b28dc
29 changed files with 172 additions and 45 deletions

View File

@ -0,0 +1,16 @@
## 概述
博查工具是一个支持自然语言搜索的 Web Search API从近百亿网页和生态内容源中搜索高质量世界知识包括新闻、图片、视频、百科、机酒、学术等。
## 配置
1. 获取API Key 
在[博查开放平台](https://open.bochaai.com/overview) 上申请 API 密钥。
![API Key](/ui/fx/img/bocha_APIKey.jpg)
2. 在函数库中配置
在函数库的博查函数面板中,点击 … > 启用参数,填写 API 密钥,并启用该函数。
![启动参数](/ui/fx/img/bocha_setting.jpg)
3. 在应用中使用
在高级编排应用中,点击添加组件->函数库->博查,设置使用参数。
![应用中使用](/ui/fx/img/bocha_app_used.jpg)

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,21 @@
## 概述
Google 搜索工具是一个实时 API可提取搜索引擎结果提供来自 Google 的结构化数据。它支持各种搜索类型,包括 Web、图像、新闻和地图。
## 配置
1. 创建 Google Custom Search Engine
在[Programmable Search Engine](https://programmablesearchengine.google.com/)中 添加 Search Engine
![google 创建引擎](/ui/fx/img/google_AddSearchEngine.jpg)
2. 获取cx参数
进入添加的引擎详情中在【基本】菜单中获取搜索引擎的ID即cx。
![google cx ](/ui/fx/img/google_cx.jpg)
3. 获取 API Key
打开 https://developers.google.com/custom-search/v1/overview?hl=zh-cn 获取API Key。
![google API Key](/ui/fx/img/google_APIKey.jpg)
4. 配置启动参数
在Google 搜索函数的启动参数中填写配置以上参数,并启用该函数。
![启动参数](/ui/fx/img/google_setting.jpg)
5. 在应用中使用
在高级编排应用中,点击添加组件->函数库->Google搜索设置使用参数。
![应用中使用](/ui/fx/img/google_app_used.jpg)

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 587 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 590 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

View File

@ -0,0 +1,17 @@
## 概述
LangSearch 是一个提供免费Web Search API和Rerank API的服务支持新闻、图像、视频等内容。它结合了关键词和向量进行混合搜索以提高准确性。
## 配置
1. 获取API Key 
在[LangSearch](https://langsearch.com/overview) 上申请 API 密钥。
![API Key](/ui/fx/img/langsearch_APIKey.jpg)
2. 在函数库中配置
在函数库的LangSearch函数面板中点击 … > 启用参数,填写 API 密钥,并启用该函数。
![启动参数](/ui/fx/img/langsearch_setting.jpg)
3. 在应用中使用
在高级编排应用中,点击添加组件->函数库->LangSearch设置使用参数。
![应用中使用](/ui/fx/img/langsearch_app_used.jpg)

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

View File

@ -0,0 +1,14 @@
## 概述
MySQL查询是一个连接MySQL数据库执行SQL查询的工具。
## 配置
 
1. 在函数库中配置启动参数
在函数库的MySQL函数面板中点击 … > 启用参数,填写数据库连接参数,并启用该函数。
![启动参数](/ui/fx/img/MySQL_setting.jpg)
2. 在应用中使用
在高级编排应用中,点击添加组件->函数库->MySQL查询设置查询内容。
![应用中使用](/ui/fx/img/MySQL_app_used.jpg)

BIN
ui/public/fx/mysql/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -0,0 +1,14 @@
## 概述
PostgreSQL查询是一个连接PostgreSQL数据库执行SQL查询的工具。
## 配置
 
1. 在函数库中配置启动参数
在函数库的PostgreSQL函数面板中点击 … > 启用参数,填写数据库连接参数,并启用该函数。
![启动参数](/ui/fx/img/PostgreSQL_setting.jpg)
2. 在应用中使用
在高级编排应用中,点击添加组件->函数库->PostgreSQL查询设置查询内容。
![应用中使用](/ui/fx/img/PostgreSQL_app_used.jpg)

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

View File

@ -15,7 +15,7 @@
:model="form"
require-asterisk-position="right"
>
<el-form-item prop="name">
<el-form-item prop="name" :label="$t('common.name')">
<el-input v-model="form.name" maxlength="64" show-word-limit></el-input>
</el-form-item>
</el-form>
@ -65,7 +65,7 @@ watch(dialogVisible, (bool) => {
}
})
const open = (row: any, edit: boolean) => {
const open = (row: any, edit?: boolean) => {
if (row) {
form.value = cloneDeep(row)
}

View File

@ -1,8 +1,10 @@
<template>
<CardBox :title="props.tool.name" :description="props.tool.desc" class="cursor">
<template #icon>
<!-- TODO -->
<LogoIcon style="width: 28px; height: 28px; display: block" />
<el-avatar v-if="isAppIcon(props.tool?.icon)" shape="square" :size="32" style="background: none">
<img :src="props.tool?.icon" alt="" />
</el-avatar>
<el-avatar v-else-if="props.tool?.name" :name="props.tool?.name" pinyinColor shape="square" :size="32" />
</template>
<template #subTitle>
<el-text class="color-secondary" size="small">
@ -14,7 +16,7 @@
{{ `${$t('common.author')}: MaxKB` }}
</span>
<div class="card-footer-operation" @click.stop>
<el-button>
<el-button @click="emit('handleDetail')">
{{ $t('common.detail') }}
</el-button>
<el-button type="primary" :loading="props.addLoading" @click="emit('handleAdd')">
@ -26,6 +28,9 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { isAppIcon } from '@/utils/common'
const props = defineProps<{
tool: any,
getSubTitle: (v: any) => string
@ -34,6 +39,7 @@ const props = defineProps<{
const emit = defineEmits<{
(e: 'handleAdd'): void;
(e: 'handleDetail'): void;
}>();
</script>

View File

@ -33,7 +33,7 @@
<el-row :gutter="16">
<el-col v-for="tool in category.tools" :key="tool.id" :span="8" class="mb-16">
<ToolCard :tool="tool" :addLoading="addLoading" :get-sub-title="getSubTitle"
@handleAdd="handleAdd(tool)" />
@handleAdd="handleOpenAdd(tool)" @handleDetail="handleDetail(tool)" />
</el-col>
</el-row>
</div>
@ -46,7 +46,7 @@
<el-row :gutter="16" v-if="filterList.length">
<el-col v-for="tool in filterList" :key="tool.id" :span="8" class="mb-16">
<ToolCard :tool="tool" :addLoading="addLoading" :get-sub-title="getSubTitle"
@handleAdd="handleAdd(tool)" />
@handleAdd="handleOpenAdd(tool)" @handleDetail="handleDetail(tool)" />
</el-col>
</el-row>
<el-empty v-else :description="$t('common.noData')" />
@ -54,6 +54,8 @@
</el-scrollbar>
</LayoutContainer>
</el-dialog>
<InternalDescDrawer ref="internalDescDrawerRef" @addFunction="handleOpenAdd" />
<AddInternalFunctionDialog ref="addInternalFunctionDialogRef" @refresh="handleAdd" />
</template>
<script setup lang="ts">
@ -62,6 +64,8 @@ import ToolApi from '@/api/tool/tool'
import { t } from '@/locales'
import ToolCard from './ToolCard.vue'
import { MsgSuccess } from '@/utils/message'
import InternalDescDrawer from './InternalDescDrawer.vue'
import AddInternalFunctionDialog from './AddInternalFunctionDialog.vue'
interface ToolCategory {
id: string
@ -74,6 +78,7 @@ const emit = defineEmits(['refresh'])
const dialogVisible = ref(false)
const loading = ref(false)
const searchValue = ref('')
const folderId = ref('')
const categories = ref<ToolCategory[]>([
{
@ -113,7 +118,8 @@ function getSubTitle(tool: any) {
return categories.value.find(i => i.id === tool.label)?.title ?? ''
}
function open() {
function open(id: string) {
folderId.value = id
filterList.value = null
dialogVisible.value = true
}
@ -146,11 +152,23 @@ const handleClick = (e: MouseEvent) => {
e.preventDefault()
}
const internalDescDrawerRef = ref<InstanceType<typeof InternalDescDrawer>>()
async function handleDetail(tool: any) {
const index = tool.icon.replace('icon.png', 'detail.md')
const response = await fetch(index)
const content = await response.text()
internalDescDrawerRef.value?.open(content, tool)
}
const addInternalFunctionDialogRef = ref<InstanceType<typeof AddInternalFunctionDialog>>()
function handleOpenAdd(data?: any, isEdit?: boolean) {
addInternalFunctionDialogRef.value?.open(data, isEdit)
}
const addLoading = ref(false)
async function handleAdd(tool: any) {
try {
// TODO
await ToolApi.addInternalTool(tool.id, { name: tool.name, folder_id: tool.folder_id }, addLoading)
await ToolApi.addInternalTool(tool.id, { name: tool.name, folder_id: folderId.value }, addLoading)
emit('refresh')
MsgSuccess(t('common.addSuccess'))
dialogVisible.value = false

View File

@ -50,9 +50,9 @@
type="primary"
class="ml-8"
v-hasPermission="[
RoleConst.WORKSPACE_MANAGE.getWorkspaceRole,
RoleConst.USER.getWorkspaceRole,
PermissionConst.TOOL_CREATE.getWorkspacePermission,
RoleConst.WORKSPACE_MANAGE.getWorkspaceRole,
RoleConst.USER.getWorkspaceRole,
PermissionConst.TOOL_CREATE.getWorkspacePermission,
]"
>
{{ $t('common.create') }}
@ -94,8 +94,7 @@
</div>
</el-dropdown-item>
</el-upload>
<!-- TODO 从工具商店创建 -->
<!-- <el-dropdown-item @click="openToolStoreDialog()">
<el-dropdown-item @click="openToolStoreDialog()">
<div class="flex align-center">
<el-avatar class="avatar-green" shape="square" :size="32">
<img src="@/assets/node/icon_tool.svg" style="width: 58%" alt="" />
@ -106,7 +105,7 @@
</div>
</div>
</div>
</el-dropdown-item> -->
</el-dropdown-item>
<el-dropdown-item @click="openCreateFolder" divided>
<div class="flex align-center">
<AppIcon iconName="app-folder" style="font-size: 32px"></AppIcon>
@ -229,19 +228,25 @@
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item v-if="item.template_id" @click.stop="addInternalFunction(item, true)">
<el-icon>
<EditPen />
</el-icon>
{{ $t('common.edit') }}
</el-dropdown-item>
<el-dropdown-item
v-if="
!item.template_id &&
hasPermission(
[
RoleConst.WORKSPACE_MANAGE.getWorkspaceRole,
RoleConst.USER.getWorkspaceRole,
!item.template_id &&
hasPermission(
[
RoleConst.WORKSPACE_MANAGE.getWorkspaceRole,
RoleConst.USER.getWorkspaceRole,
PermissionConst.TOOL_EDIT
.getWorkspacePermissionWorkspaceManageRole,
PermissionConst.TOOL_EDIT.getWorkspacePermission,
],
'OR',
)
PermissionConst.TOOL_EDIT.getWorkspacePermission,
],
'OR',
)
"
@click.stop="openCreateDialog(item)"
>
@ -252,15 +257,15 @@
</el-dropdown-item>
<el-dropdown-item
v-if="
!item.template_id &&
hasPermission(
[
RoleConst.WORKSPACE_MANAGE.getWorkspaceRole,
RoleConst.USER.getWorkspaceRole,
PermissionConst.TOOL_EXPORT.getWorkspacePermission,
],
'OR',
)
!item.template_id &&
hasPermission(
[
RoleConst.WORKSPACE_MANAGE.getWorkspaceRole,
RoleConst.USER.getWorkspaceRole,
PermissionConst.TOOL_EXPORT.getWorkspacePermission,
],
'OR',
)
"
@click.stop="copyTool(item)"
>
@ -276,15 +281,15 @@
</el-dropdown-item>
<el-dropdown-item
v-if="
!item.template_id &&
hasPermission(
[
RoleConst.WORKSPACE_MANAGE.getWorkspaceRole,
RoleConst.USER.getWorkspaceRole,
PermissionConst.TOOL_EXPORT.getWorkspacePermission,
],
'OR',
)
!item.template_id &&
hasPermission(
[
RoleConst.WORKSPACE_MANAGE.getWorkspaceRole,
RoleConst.USER.getWorkspaceRole,
PermissionConst.TOOL_EXPORT.getWorkspacePermission,
],
'OR',
)
"
@click.stop="exportTool(item)"
>
@ -316,6 +321,7 @@
<ToolFormDrawer ref="ToolFormDrawerRef" @refresh="refresh" :title="ToolDrawertitle" />
<CreateFolderDialog ref="CreateFolderDialogRef" @refresh="refreshFolder" v-if="!isShared" />
<ToolStoreDialog ref="toolStoreDialogRef" @refresh="refresh" />
<AddInternalFunctionDialog ref="addInternalFunctionDialogRef" @refresh="confirmAddInternalFunction" />
</LayoutContainer>
</template>
@ -335,6 +341,7 @@ import { hasPermission } from '@/utils/permission/index'
import { FolderSource } from '@/enums/common'
import { ComplexPermission } from '@/utils/permission/type'
import ToolStoreDialog from './component/ToolStoreDialog.vue'
import AddInternalFunctionDialog from './component/AddInternalFunctionDialog.vue'
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
import permissionMap from '@/permission'
import { useRoute } from 'vue-router'
@ -466,7 +473,7 @@ async function changeState(row: any) {
}
}
function refresh(data: any) {
function refresh(data?: any) {
if (data) {
const index = toolList.value.findIndex((v) => v.id === data.id)
// if (user.userInfo && data.user_id === user.userInfo.id) {
@ -528,7 +535,21 @@ function configInitParams(item: any) {
const toolStoreDialogRef = ref<InstanceType<typeof ToolStoreDialog>>()
function openToolStoreDialog() {
toolStoreDialogRef.value?.open()
toolStoreDialogRef.value?.open(currentFolder.value.id)
}
const addInternalFunctionDialogRef = ref<InstanceType<typeof AddInternalFunctionDialog>>()
function addInternalFunction(data?: any, isEdit?: boolean) {
addInternalFunctionDialogRef.value?.open(data, isEdit)
}
function confirmAddInternalFunction(data?: any, isEdit?: boolean) {
if (isEdit) {
ToolApi.putTool(data?.id as string, { name: data.name }, loading).then((res) => {
MsgSuccess(t('common.saveSuccess'))
refresh()
})
}
}
const elUploadRef = ref()