feat: toolStoreDialog
This commit is contained in:
parent
9777c92e34
commit
1287da6ed0
@ -2,7 +2,7 @@ import { Result } from '@/request/Result'
|
|||||||
import { get, post, del, put, exportFile } from '@/request/index'
|
import { get, post, del, put, exportFile } from '@/request/index'
|
||||||
import { type Ref } from 'vue'
|
import { type Ref } from 'vue'
|
||||||
import type { pageRequest } from '@/api/type/common'
|
import type { pageRequest } from '@/api/type/common'
|
||||||
import type { toolData } from '@/api/type/tool'
|
import type { toolData,AddInternalToolParam } from '@/api/type/tool'
|
||||||
|
|
||||||
|
|
||||||
import useStore from '@/stores'
|
import useStore from '@/stores'
|
||||||
@ -84,7 +84,7 @@ const getToolById: (tool_id: string, loading?: Ref<boolean>) => Promise<Result<a
|
|||||||
* @param 参数 tool_id
|
* @param 参数 tool_id
|
||||||
*/
|
*/
|
||||||
const delTool: (
|
const delTool: (
|
||||||
tool_id: String,
|
tool_id: string,
|
||||||
loading?: Ref<boolean>
|
loading?: Ref<boolean>
|
||||||
) => Promise<Result<boolean>> = (tool_id, loading) => {
|
) => Promise<Result<boolean>> = (tool_id, loading) => {
|
||||||
return del(`${prefix.value}/${tool_id}`, undefined, {}, loading)
|
return del(`${prefix.value}/${tool_id}`, undefined, {}, loading)
|
||||||
@ -128,6 +128,26 @@ const postPylint: (code: string, loading?: Ref<boolean>) => Promise<Result<any>>
|
|||||||
return post(`${prefix.value}/pylint`, { code }, {}, loading)
|
return post(`${prefix.value}/pylint`, { code }, {}, loading)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工具商店-系统内置列表
|
||||||
|
*/
|
||||||
|
const getInternalToolList: (
|
||||||
|
param?: any,
|
||||||
|
loading?: Ref<boolean>,
|
||||||
|
) => Promise<Result<any>> = (param, loading) => {
|
||||||
|
return get('/workspace/internal/tool', param, loading)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工具商店-添加系统内置
|
||||||
|
*/
|
||||||
|
const addInternalTool: (tool_id: string, param: AddInternalToolParam, loading?: Ref<boolean>) => Promise<Result<any>> = (
|
||||||
|
tool_id,
|
||||||
|
param,
|
||||||
|
loading,
|
||||||
|
) => {
|
||||||
|
return post(`${prefix.value}/${tool_id}/add_internal_tool`, param, undefined, loading)
|
||||||
|
}
|
||||||
export default {
|
export default {
|
||||||
getToolList,
|
getToolList,
|
||||||
getToolListPage,
|
getToolListPage,
|
||||||
@ -139,5 +159,7 @@ export default {
|
|||||||
postPylint,
|
postPylint,
|
||||||
exportTool,
|
exportTool,
|
||||||
putToolIcon,
|
putToolIcon,
|
||||||
delTool
|
delTool,
|
||||||
|
getInternalToolList,
|
||||||
|
addInternalTool
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,4 +10,9 @@ interface toolData {
|
|||||||
folder_id?: string
|
folder_id?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type { toolData }
|
interface AddInternalToolParam {
|
||||||
|
name: string,
|
||||||
|
folder_id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type { toolData, AddInternalToolParam }
|
||||||
|
|||||||
@ -87,4 +87,5 @@ export default {
|
|||||||
otherSetting: 'Other Settings',
|
otherSetting: 'Other Settings',
|
||||||
username: 'username',
|
username: 'username',
|
||||||
importCreate: 'Import Create',
|
importCreate: 'Import Create',
|
||||||
|
detail: 'Detail'
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,17 @@ export default {
|
|||||||
editTool: 'Edit Tool',
|
editTool: 'Edit Tool',
|
||||||
copyTool: 'Copy Tool',
|
copyTool: 'Copy Tool',
|
||||||
importTool: 'Import Tool',
|
importTool: 'Import Tool',
|
||||||
|
toolStore: {
|
||||||
|
title: 'Tool Store',
|
||||||
|
createFromToolStore: 'Create from Tool Store',
|
||||||
|
recommend: 'Recommended',
|
||||||
|
webSearch: 'Web Search',
|
||||||
|
databaseQuery: 'Database Query',
|
||||||
|
image: 'Image',
|
||||||
|
developer: 'Developer',
|
||||||
|
communication: 'Communication',
|
||||||
|
searchResult: '{count} search results for'
|
||||||
|
},
|
||||||
searchBar: {
|
searchBar: {
|
||||||
placeholder: 'Search by tool name',
|
placeholder: 'Search by tool name',
|
||||||
},
|
},
|
||||||
|
|||||||
@ -91,4 +91,5 @@ export default {
|
|||||||
otherSetting: '其他设置',
|
otherSetting: '其他设置',
|
||||||
username: '用户名',
|
username: '用户名',
|
||||||
importCreate: '导入创建',
|
importCreate: '导入创建',
|
||||||
|
detail: '详情'
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,17 @@ export default {
|
|||||||
editTool: '编辑工具',
|
editTool: '编辑工具',
|
||||||
copyTool: '复制函数',
|
copyTool: '复制函数',
|
||||||
importTool: '导入函数',
|
importTool: '导入函数',
|
||||||
|
toolStore: {
|
||||||
|
title: '工具商店',
|
||||||
|
createFromToolStore: '从工具商店创建',
|
||||||
|
recommend: '推荐',
|
||||||
|
webSearch: '联网搜索',
|
||||||
|
databaseQuery: '数据库查询',
|
||||||
|
image: '图像',
|
||||||
|
developer: '开发者',
|
||||||
|
communication: '通信',
|
||||||
|
searchResult: '的搜索结果 {count} 个'
|
||||||
|
},
|
||||||
enabled: '启用',
|
enabled: '启用',
|
||||||
disabled: {
|
disabled: {
|
||||||
confirmTitle: '是否禁用工具:',
|
confirmTitle: '是否禁用工具:',
|
||||||
|
|||||||
@ -87,4 +87,5 @@ export default {
|
|||||||
otherSetting: '其他設定',
|
otherSetting: '其他設定',
|
||||||
username: '用戶名',
|
username: '用戶名',
|
||||||
importCreate: '導入創建',
|
importCreate: '導入創建',
|
||||||
|
detail: '详情'
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,17 @@ export default {
|
|||||||
editTool: '編輯工具',
|
editTool: '編輯工具',
|
||||||
copyTool: '複製工具',
|
copyTool: '複製工具',
|
||||||
importTool: '匯入工具',
|
importTool: '匯入工具',
|
||||||
|
toolStore: {
|
||||||
|
title: '工具商店',
|
||||||
|
createFromToolStore: '從工具商店創建',
|
||||||
|
recommend: '推薦',
|
||||||
|
webSearch: '聯網搜索',
|
||||||
|
databaseQuery: '數據庫查詢',
|
||||||
|
image: '圖像',
|
||||||
|
developer: '開發者',
|
||||||
|
communication: '通信',
|
||||||
|
searchResult: '的搜索結果 {count} 個'
|
||||||
|
},
|
||||||
searchBar: {
|
searchBar: {
|
||||||
placeholder: '按工具名稱搜尋',
|
placeholder: '按工具名稱搜尋',
|
||||||
},
|
},
|
||||||
|
|||||||
66
ui/src/views/tool/component/ToolCard.vue
Normal file
66
ui/src/views/tool/component/ToolCard.vue
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<template>
|
||||||
|
<CardBox :title="props.tool.name" :description="props.tool.desc" class="cursor">
|
||||||
|
<template #icon>
|
||||||
|
<!-- TODO -->
|
||||||
|
<LogoIcon style="width: 28px; height: 28px; display: block" />
|
||||||
|
</template>
|
||||||
|
<template #subTitle>
|
||||||
|
<el-text class="color-secondary" size="small">
|
||||||
|
{{ getSubTitle(props.tool) }}
|
||||||
|
</el-text>
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<span class="card-footer-left color-secondary">
|
||||||
|
{{ `${$t('common.author')}: MaxKB` }}
|
||||||
|
</span>
|
||||||
|
<div class="card-footer-operation" @click.stop>
|
||||||
|
<el-button>
|
||||||
|
{{ $t('common.detail') }}
|
||||||
|
</el-button>
|
||||||
|
<el-button type="primary" :loading="props.addLoading" @click="emit('handleAdd')">
|
||||||
|
{{ $t('common.add') }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</CardBox>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
const props = defineProps<{
|
||||||
|
tool: any,
|
||||||
|
getSubTitle: (v: any) => string
|
||||||
|
addLoading: boolean
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'handleAdd'): void;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.el-card {
|
||||||
|
:deep(.card-footer) {
|
||||||
|
&>div:first-of-type {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-footer-operation {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.card-footer-left {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-footer-operation {
|
||||||
|
display: flex !important;
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
207
ui/src/views/tool/component/ToolStoreDialog.vue
Normal file
207
ui/src/views/tool/component/ToolStoreDialog.vue
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog v-model="dialogVisible" width="1000" append-to-body class="tool-store-dialog" align-center
|
||||||
|
:close-on-click-modal="false" :close-on-press-escape="false">
|
||||||
|
<template #header="{ titleId }">
|
||||||
|
<div class="flex-between mb-8">
|
||||||
|
<h4 :id="titleId" class="medium">
|
||||||
|
{{ $t('views.tool.toolStore.title') }}
|
||||||
|
</h4>
|
||||||
|
|
||||||
|
<div class="flex align-center" style="margin-right: 28px;">
|
||||||
|
<el-input v-model="searchValue" :placeholder="$t('common.search')" prefix-icon="Search" class="w-240 mr-8"
|
||||||
|
clearable @change="getList" />
|
||||||
|
<el-divider direction="vertical" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<LayoutContainer v-loading="loading">
|
||||||
|
<template #left>
|
||||||
|
<el-anchor direction="vertical" :offset="130" type="default" container=".category-scrollbar"
|
||||||
|
@click="handleClick">
|
||||||
|
<el-anchor-link v-for="category in categories" :key="category.id" :href="`#category-${category.id}`"
|
||||||
|
:title="category.title" />
|
||||||
|
</el-anchor>
|
||||||
|
</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 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">
|
||||||
|
<ToolCard :tool="tool" :addLoading="addLoading" :get-sub-title="getSubTitle"
|
||||||
|
@handleAdd="handleAdd(tool)" />
|
||||||
|
</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="8" class="mb-16">
|
||||||
|
<ToolCard :tool="tool" :addLoading="addLoading" :get-sub-title="getSubTitle"
|
||||||
|
@handleAdd="handleAdd(tool)" />
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-empty v-else :description="$t('common.noData')" />
|
||||||
|
</div>
|
||||||
|
</el-scrollbar>
|
||||||
|
</LayoutContainer>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { onBeforeMount, ref } from 'vue'
|
||||||
|
import ToolApi from '@/api/tool/tool'
|
||||||
|
import { t } from '@/locales'
|
||||||
|
import ToolCard from './ToolCard.vue'
|
||||||
|
|
||||||
|
interface ToolCategory {
|
||||||
|
id: string
|
||||||
|
title: string
|
||||||
|
tools: any[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const emit = defineEmits(['refresh'])
|
||||||
|
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const loading = ref(false)
|
||||||
|
const searchValue = ref('')
|
||||||
|
|
||||||
|
const categories = ref<ToolCategory[]>([
|
||||||
|
{
|
||||||
|
id: 'recommend',
|
||||||
|
title: t('views.tool.toolStore.recommend'),
|
||||||
|
tools: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'web_search',
|
||||||
|
title: t('views.tool.toolStore.webSearch'),
|
||||||
|
tools: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'database_search',
|
||||||
|
title: t('views.tool.toolStore.databaseQuery'),
|
||||||
|
tools: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'image',
|
||||||
|
title: t('views.tool.toolStore.image'),
|
||||||
|
tools: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'developer',
|
||||||
|
title: t('views.tool.toolStore.developer'),
|
||||||
|
tools: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'communication',
|
||||||
|
title: t('views.tool.toolStore.communication'),
|
||||||
|
tools: []
|
||||||
|
}
|
||||||
|
])
|
||||||
|
const filterList = ref<any>(null)
|
||||||
|
|
||||||
|
function getSubTitle(tool: any) {
|
||||||
|
return categories.value.find(i => i.id === tool.label)?.title ?? ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
filterList.value = null
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
onBeforeMount(() => {
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
|
||||||
|
async function getList() {
|
||||||
|
try {
|
||||||
|
const res = await ToolApi.getInternalToolList({ name: searchValue.value }, loading)
|
||||||
|
if (searchValue.value.length) {
|
||||||
|
filterList.value = res.data
|
||||||
|
} else {
|
||||||
|
filterList.value = null
|
||||||
|
categories.value.forEach(category => {
|
||||||
|
if (category.id === 'recommend') {
|
||||||
|
category.tools = res.data
|
||||||
|
} else {
|
||||||
|
category.tools = res.data.filter((tool: any) => tool.label === category.id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClick = (e: MouseEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
|
|
||||||
|
const addLoading = ref(false)
|
||||||
|
async function handleAdd(tool: any) {
|
||||||
|
try {
|
||||||
|
await ToolApi.addInternalTool(tool.id, { name: tool.name, folder_id: tool.folder_id }, addLoading)
|
||||||
|
dialogVisible.value = false
|
||||||
|
emit('refresh')
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ open })
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.tool-store-dialog {
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
.el-dialog__header {
|
||||||
|
padding: 12px 20px 4px 24px;
|
||||||
|
border-bottom: 1px solid var(--el-border-color-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout-container__left {
|
||||||
|
background-color: var(--app-layout-bg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-anchor {
|
||||||
|
background-color: var(--app-layout-bg-color);
|
||||||
|
|
||||||
|
.el-anchor__marker {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-anchor__list {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-anchor__item {
|
||||||
|
.el-anchor__link {
|
||||||
|
padding: 8px 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--el-text-color-primary);
|
||||||
|
border-radius: 6px;
|
||||||
|
|
||||||
|
&.is-active {
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
background-color: #3370ff1a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.category-scrollbar {
|
||||||
|
max-height: calc(100vh - 260px);
|
||||||
|
min-height: 500px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -97,6 +97,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
|
<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="" />
|
||||||
|
</el-avatar>
|
||||||
|
<div class="pre-wrap ml-8">
|
||||||
|
<div class="lighter">{{ $t('views.tool.toolStore.createFromToolStore') }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-dropdown-item>
|
||||||
<el-dropdown-item @click="openCreateFolder" divided>
|
<el-dropdown-item @click="openCreateFolder" divided>
|
||||||
<div class="flex align-center">
|
<div class="flex align-center">
|
||||||
<AppIcon iconName="app-folder" style="font-size: 32px"></AppIcon>
|
<AppIcon iconName="app-folder" style="font-size: 32px"></AppIcon>
|
||||||
@ -312,6 +322,7 @@
|
|||||||
<InitParamDrawer ref="InitParamDrawerRef" @refresh="refresh" />
|
<InitParamDrawer ref="InitParamDrawerRef" @refresh="refresh" />
|
||||||
<ToolFormDrawer ref="ToolFormDrawerRef" @refresh="refresh" :title="ToolDrawertitle" />
|
<ToolFormDrawer ref="ToolFormDrawerRef" @refresh="refresh" :title="ToolDrawertitle" />
|
||||||
<CreateFolderDialog ref="CreateFolderDialogRef" @refresh="refreshFolder" />
|
<CreateFolderDialog ref="CreateFolderDialogRef" @refresh="refreshFolder" />
|
||||||
|
<ToolStoreDialog ref="toolStoreDialogRef" @refresh="refresh" />
|
||||||
</LayoutContainer>
|
</LayoutContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -331,6 +342,7 @@ import { EditionConst, PermissionConst, RoleConst } from '@/utils/permission/dat
|
|||||||
import { hasPermission } from '@/utils/permission/index'
|
import { hasPermission } from '@/utils/permission/index'
|
||||||
import { FolderSource } from '@/enums/common'
|
import { FolderSource } from '@/enums/common'
|
||||||
import { ComplexPermission } from '@/utils/permission/type'
|
import { ComplexPermission } from '@/utils/permission/type'
|
||||||
|
import ToolStoreDialog from './component/ToolStoreDialog.vue'
|
||||||
|
|
||||||
const { folder, user } = useStore()
|
const { folder, user } = useStore()
|
||||||
|
|
||||||
@ -506,6 +518,11 @@ function configInitParams(item: any) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const toolStoreDialogRef = ref<InstanceType<typeof ToolStoreDialog>>()
|
||||||
|
function openToolStoreDialog() {
|
||||||
|
toolStoreDialogRef.value?.open()
|
||||||
|
}
|
||||||
|
|
||||||
const elUploadRef = ref()
|
const elUploadRef = ref()
|
||||||
function importTool(file: any) {
|
function importTool(file: any) {
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user