refactor: dropdownMenu

This commit is contained in:
teukkk 2025-06-30 18:06:18 +08:00
parent 3e4aac3557
commit e5d26301c7
5 changed files with 67 additions and 44 deletions

View File

@ -79,6 +79,11 @@ export default {
cannotEndNode: 'This node cannot be used as an end node'
},
nodes: {
classify: {
aiCapability: 'AI capability',
businessLogic: 'Business logic',
other: 'Other'
},
startNode: {
label: 'Start',
question: 'User Question',

View File

@ -80,6 +80,11 @@ export default {
cannotEndNode: '节点不能当做结束节点'
},
nodes: {
classify: {
aiCapability: 'AI能力',
businessLogic: '业务逻辑',
other: '其他'
},
startNode: {
label: '开始',
question: '用户问题',

View File

@ -80,6 +80,11 @@ export default {
cannotEndNode: '節點不能當做結束節點'
},
nodes: {
classify: {
aiCapability: 'AI能力',
businessLogic: '業務邏輯',
other: '其他'
},
startNode: {
label: '開始',
question: '用戶問題',

View File

@ -1,12 +1,9 @@
<template>
<div v-show="show" class="workflow-dropdown-menu border border-r-6">
<el-tabs v-model="activeName" class="workflow-dropdown-tabs">
<div style="display: flex; width: 100%; justify-content: center" class="mb-4">
<el-input
v-model="search_text"
style="width: 240px"
:placeholder="$t('views.applicationWorkflow.searchBar.placeholder')"
>
<div style="display: flex; width: 100%; justify-content: center;" class="mb-12">
<el-input v-model="search_text" class="mr-12 ml-12"
:placeholder="$t('views.applicationWorkflow.searchBar.placeholder')">
<template #suffix>
<el-icon class="el-input__icon"><search /></el-icon>
</template>
@ -16,17 +13,27 @@
<el-tab-pane :label="$t('views.applicationWorkflow.baseComponent')" name="base">
<el-scrollbar height="400">
<div v-if="filter_menu_nodes.length > 0">
<template v-for="(item, index) in filter_menu_nodes" :key="index">
<div
class="workflow-dropdown-item cursor flex p-8-12"
@click.stop="clickNodes(item)"
@mousedown.stop="onmousedown(item)"
>
<component :is="iconComponent(`${item.type}-icon`)" class="mr-8 mt-4" :size="32" />
<div class="pre-wrap">
<div class="lighter">{{ item.label }}</div>
<el-text type="info" size="small">{{ item.text }}</el-text>
</div>
<template v-for="(node, index) in filter_menu_nodes" :key="index">
<el-text type="info" size="small" class="color-secondary ml-12">{{ node.label }}</el-text>
<div class="flex-wrap mt-8">
<template v-for="(item, index) in node.list" :key="index">
<el-popover placement="right" :width="280">
<template #reference>
<div class="flex align-center border border-r-6 mb-12 p-8-12 cursor ml-12" style="width: 39%; " @click.stop="clickNodes(item)"
@mousedown.stop="onmousedown(item)">
<component :is="iconComponent(`${item.type}-icon`)" class="mr-8" :size="32" />
<div class="lighter">{{ item.label }}</div>
</div>
</template>
<template #default>
<div class="flex align-center mb-8">
<component :is="iconComponent(`${item.type}-icon`)" class="mr-8" :size="32" />
<div class="lighter color-text-primary">{{ item.label }}</div>
</div>
<el-text type="info" size="small" class="color-secondary lighter">{{ item.text }}</el-text>
</template>
</el-popover>
</template>
</div>
</template>
</div>
@ -167,10 +174,21 @@ const filter_application_list = computed(() => {
})
const filter_menu_nodes = computed(() => {
return menuNodes.filter((item) =>
item.label.toLocaleLowerCase().includes(search_text.value.toLocaleLowerCase()),
)
})
if (!search_text.value) return menuNodes;
const searchTerm = search_text.value.toLowerCase();
return menuNodes.reduce((result, item) => {
const filteredList = item.list.filter(listItem =>
listItem.label.toLowerCase().includes(searchTerm)
);
if (filteredList.length) {
result.push({ ...item, list: filteredList });
}
return result;
}, []);
});
function clickNodes(item: any, data?: any, type?: string) {
if (data) {
item['properties']['stepName'] = data.name
@ -197,10 +215,10 @@ function clickNodes(item: any, data?: any, type?: string) {
...(!fileUploadSetting
? {}
: {
...(fileUploadSetting.document ? { document_list: [] } : {}),
...(fileUploadSetting.image ? { image_list: [] } : {}),
...(fileUploadSetting.audio ? { audio_list: [] } : {}),
}),
...(fileUploadSetting.document ? { document_list: [] } : {}),
...(fileUploadSetting.image ? { image_list: [] } : {}),
...(fileUploadSetting.audio ? { audio_list: [] } : {}),
}),
}
} else {
item['properties']['node_data'] = {
@ -242,10 +260,10 @@ function onmousedown(item: any, data?: any, type?: string) {
...(!fileUploadSetting
? {}
: {
...(fileUploadSetting.document ? { document_list: [] } : {}),
...(fileUploadSetting.image ? { image_list: [] } : {}),
...(fileUploadSetting.audio ? { audio_list: [] } : {}),
}),
...(fileUploadSetting.document ? { document_list: [] } : {}),
...(fileUploadSetting.image ? { image_list: [] } : {}),
...(fileUploadSetting.audio ? { audio_list: [] } : {}),
}),
}
} else {
item['properties']['node_data'] = {
@ -285,7 +303,7 @@ onMounted(() => {
top: 49px;
right: 122px;
z-index: 99;
width: 268px;
width: 400px;
box-shadow: 0px 4px 8px 0px var(--app-text-color-light-1);
background: #ffffff;
padding-bottom: 8px;

View File

@ -338,20 +338,10 @@ export const textToSpeechNode = {
}
}
export const menuNodes = [
aiChatNode,
imageUnderstandNode,
imageGenerateNode,
searchKnowledgeNode,
rerankerNode,
conditionNode,
replyNode,
formNode,
questionNode,
documentExtractNode,
speechToTextNode,
textToSpeechNode,
variableAssignNode,
mcpNode
{ label: t('views.applicationWorkflow.nodes.classify.aiCapability'), list: [aiChatNode, questionNode, imageGenerateNode, imageUnderstandNode, textToSpeechNode, speechToTextNode] },
{ label: t('views.knowledge.title'), list: [searchKnowledgeNode, rerankerNode] },
{ label: t('views.applicationWorkflow.nodes.classify.businessLogic'), list: [conditionNode, formNode, variableAssignNode, replyNode] },
{ label: t('views.applicationWorkflow.nodes.classify.other'), list: [mcpNode, documentExtractNode] },
]
/**