|
| 1 | +<template> |
| 2 | + <div |
| 3 | + v-show="show" |
| 4 | + class="workflow-dropdown-menu border border-r-6 white-bg" |
| 5 | + :style="{ width: activeName === 'base' ? '400px' : '640px' }" |
| 6 | + > |
| 7 | + <el-tabs v-model="activeName" class="workflow-dropdown-tabs" @tab-change="handleClick"> |
| 8 | + <div |
| 9 | + v-show="activeName === 'base'" |
| 10 | + style="display: flex; width: 100%; justify-content: center" |
| 11 | + class="mb-12 mt-12" |
| 12 | + > |
| 13 | + <el-input |
| 14 | + v-model="search_text" |
| 15 | + class="mr-12 ml-12" |
| 16 | + :placeholder="$t('common.searchBar.placeholder')" |
| 17 | + > |
| 18 | + <template #suffix> |
| 19 | + <el-icon class="el-input__icon"> |
| 20 | + <search /> |
| 21 | + </el-icon> |
| 22 | + </template> |
| 23 | + </el-input> |
| 24 | + </div> |
| 25 | + |
| 26 | + <el-tab-pane :label="$t('views.workflow.baseComponent')" name="base"> |
| 27 | + <el-scrollbar height="400"> |
| 28 | + <div v-if="filter_menu_nodes.length > 0"> |
| 29 | + <template v-for="(node, index) in filter_menu_nodes" :key="index"> |
| 30 | + <el-text type="info" size="small" class="color-secondary ml-12">{{ |
| 31 | + node.label |
| 32 | + }}</el-text> |
| 33 | + <div class="flex-wrap" style="gap: 12px; padding: 12px"> |
| 34 | + <template v-for="(item, index) in node.list" :key="index"> |
| 35 | + <el-popover placement="right" :width="280" :show-after="500"> |
| 36 | + <template #reference> |
| 37 | + <div |
| 38 | + class="list-item flex align-center border border-r-6 p-8-12 cursor" |
| 39 | + style="width: calc(50% - 6px)" |
| 40 | + @click.stop="clickNodes(item)" |
| 41 | + @mousedown.stop="onmousedown(item)" |
| 42 | + > |
| 43 | + <component |
| 44 | + :is="iconComponent(`${item.type}-icon`)" |
| 45 | + class="mr-8" |
| 46 | + :size="20" |
| 47 | + /> |
| 48 | + <div class="lighter">{{ item.label }}</div> |
| 49 | + </div> |
| 50 | + </template> |
| 51 | + <template #default> |
| 52 | + <div class="flex align-center mb-8"> |
| 53 | + <component |
| 54 | + :is="iconComponent(`${item.type}-icon`)" |
| 55 | + class="mr-8" |
| 56 | + :size="32" |
| 57 | + /> |
| 58 | + <div class="lighter color-text-primary">{{ item.label }}</div> |
| 59 | + </div> |
| 60 | + <el-text type="info" size="small" class="color-secondary lighter">{{ |
| 61 | + item.text |
| 62 | + }}</el-text> |
| 63 | + </template> |
| 64 | + </el-popover> |
| 65 | + </template> |
| 66 | + </div> |
| 67 | + </template> |
| 68 | + </div> |
| 69 | + <div v-else class="ml-16 mt-8"> |
| 70 | + <el-text type="info">{{ $t('views.workflow.tip.noData') }}</el-text> |
| 71 | + </div> |
| 72 | + </el-scrollbar> |
| 73 | + </el-tab-pane> |
| 74 | + <!-- 工具 --> |
| 75 | + <el-tab-pane :label="$t('views.tool.title')" name="CUSTOM_TOOL"> |
| 76 | + <LayoutContainer> |
| 77 | + <template #left> |
| 78 | + <folder-tree |
| 79 | + :source="SourceTypeEnum.TOOL" |
| 80 | + :data="toolTreeData" |
| 81 | + :currentNodeKey="folder.currentFolder?.id" |
| 82 | + @handleNodeClick="folderClickHandle" |
| 83 | + :shareTitle="$t('views.shared.shared_tool')" |
| 84 | + :showShared="permissionPrecise['is_share']()" |
| 85 | + :canOperation="false" |
| 86 | + :treeStyle="{ height: '400px' }" |
| 87 | + /> |
| 88 | + </template> |
| 89 | + <el-scrollbar height="450"> |
| 90 | + <NodeContent |
| 91 | + :list="toolList" |
| 92 | + @clickNodes="(val: any) => clickNodes(toolLibNode, val)" |
| 93 | + @onmousedown="(val: any) => onmousedown(toolLibNode, val)" |
| 94 | + /> |
| 95 | + </el-scrollbar> |
| 96 | + </LayoutContainer> |
| 97 | + </el-tab-pane> |
| 98 | + </el-tabs> |
| 99 | + </div> |
| 100 | +</template> |
| 101 | +<script setup lang="ts"> |
| 102 | +import { ref, onMounted, computed, inject } from 'vue' |
| 103 | +import { getMenuNodes, toolLibNode, applicationNode } from '@/workflow/common/data' |
| 104 | +import { iconComponent } from '@/workflow/icons/utils' |
| 105 | +import { loadSharedApi } from '@/utils/dynamics-api/shared-api' |
| 106 | +import useStore from '@/stores' |
| 107 | +import NodeContent from './NodeContent.vue' |
| 108 | +import { SourceTypeEnum } from '@/enums/common' |
| 109 | +import permissionMap from '@/permission' |
| 110 | +import { useRoute } from 'vue-router' |
| 111 | +import { WorkflowKind, WorkflowMode } from '@/enums/application' |
| 112 | +const workflowModel = inject('workflowMode') as WorkflowMode |
| 113 | +const route = useRoute() |
| 114 | +const { user, folder } = useStore() |
| 115 | +
|
| 116 | +const menuNodes = getMenuNodes(workflowModel || WorkflowMode.Application)?.filter( |
| 117 | + (item, index) => index > 0, |
| 118 | +) |
| 119 | +const search_text = ref<string>('') |
| 120 | +const props = defineProps({ |
| 121 | + show: { |
| 122 | + type: Boolean, |
| 123 | + default: false, |
| 124 | + }, |
| 125 | + id: { |
| 126 | + type: String, |
| 127 | + default: '', |
| 128 | + }, |
| 129 | + workflowRef: Object, |
| 130 | +}) |
| 131 | +
|
| 132 | +const emit = defineEmits(['clickNodes', 'onmousedown']) |
| 133 | +
|
| 134 | +const apiType = computed(() => { |
| 135 | + if (route.path.includes('resource-management')) { |
| 136 | + return 'systemManage' |
| 137 | + } else { |
| 138 | + return 'workspace' |
| 139 | + } |
| 140 | +}) |
| 141 | +const permissionPrecise = computed(() => { |
| 142 | + return permissionMap['tool'][apiType.value] |
| 143 | +}) |
| 144 | +
|
| 145 | +const loading = ref(false) |
| 146 | +const activeName = ref('base') |
| 147 | +
|
| 148 | +const filter_menu_nodes = computed(() => { |
| 149 | + if (!search_text.value) return menuNodes || [] |
| 150 | + const searchTerm = search_text.value.toLowerCase() |
| 151 | +
|
| 152 | + return (menuNodes || []).reduce((result: any[], item) => { |
| 153 | + const filteredList = item.list.filter((listItem) => |
| 154 | + listItem.label.toLowerCase().includes(searchTerm), |
| 155 | + ) |
| 156 | +
|
| 157 | + if (filteredList.length) { |
| 158 | + result.push({ ...item, list: filteredList }) |
| 159 | + } |
| 160 | +
|
| 161 | + return result |
| 162 | + }, []) |
| 163 | +}) |
| 164 | +function clickNodes(item: any, data?: any) { |
| 165 | + if (data) { |
| 166 | + item['properties']['stepName'] = data.name |
| 167 | +
|
| 168 | + if (data.tool_type == 'DATA_SOURCE') { |
| 169 | + item['properties'].kind = WorkflowKind.DataSource |
| 170 | + } |
| 171 | + item['properties']['node_data'] = { |
| 172 | + ...data, |
| 173 | + tool_lib_id: data.id, |
| 174 | + input_field_list: data.input_field_list.map((field: any) => ({ |
| 175 | + ...field, |
| 176 | + value: field.source == 'reference' ? [] : '', |
| 177 | + })), |
| 178 | + } |
| 179 | + } |
| 180 | + props.workflowRef?.addNode(item) |
| 181 | +
|
| 182 | + emit('clickNodes', item) |
| 183 | +} |
| 184 | +
|
| 185 | +function onmousedown(item: any, data?: any) { |
| 186 | + if (data) { |
| 187 | + item['properties']['stepName'] = data.name |
| 188 | + if (data.tool_type == 'DATA_SOURCE') { |
| 189 | + item['properties'].kind = WorkflowKind.DataSource |
| 190 | + } |
| 191 | + item['properties']['node_data'] = { |
| 192 | + ...data, |
| 193 | + tool_lib_id: data.id, |
| 194 | + input_field_list: data.input_field_list.map((field: any) => ({ |
| 195 | + ...field, |
| 196 | + value: field.source == 'reference' ? [] : '', |
| 197 | + })), |
| 198 | + } |
| 199 | + } |
| 200 | + props.workflowRef?.onmousedown(item) |
| 201 | + emit('onmousedown', item) |
| 202 | +} |
| 203 | +
|
| 204 | +const toolTreeData = ref<any[]>([]) |
| 205 | +const toolList = ref<any[]>([]) |
| 206 | +
|
| 207 | +async function getToolFolder() { |
| 208 | + const res: any = await folder.asyncGetFolder(SourceTypeEnum.TOOL, {}, loading) |
| 209 | + toolTreeData.value = res.data |
| 210 | + folder.setCurrentFolder(res.data?.[0] || {}) |
| 211 | +} |
| 212 | +
|
| 213 | +async function getToolList() { |
| 214 | + const res = await loadSharedApi({ |
| 215 | + type: 'tool', |
| 216 | + isShared: folder.currentFolder?.id === 'share', |
| 217 | + systemType: 'workspace', |
| 218 | + }).getToolList({ |
| 219 | + folder_id: folder.currentFolder?.id || user.getWorkspaceId(), |
| 220 | + tool_type: activeName.value == 'DATA_SOURCE_TOOL' ? 'DATA_SOURCE' : 'CUSTOM', |
| 221 | + }) |
| 222 | + toolList.value = res.data?.tools || res.data || [] |
| 223 | + toolList.value = toolList.value?.filter((item: any) => item.is_active) |
| 224 | +} |
| 225 | +
|
| 226 | +function folderClickHandle(row: any) { |
| 227 | + folder.setCurrentFolder(row) |
| 228 | + if (['DATA_SOURCE_TOOL', 'CUSTOM_TOOL'].includes(activeName.value)) { |
| 229 | + getToolList() |
| 230 | + } |
| 231 | +} |
| 232 | +
|
| 233 | +async function handleClick(val: string) { |
| 234 | + if (['DATA_SOURCE_TOOL', 'CUSTOM_TOOL'].includes(val)) { |
| 235 | + await getToolFolder() |
| 236 | + getToolList() |
| 237 | + } |
| 238 | +} |
| 239 | +
|
| 240 | +onMounted(() => {}) |
| 241 | +</script> |
| 242 | +<style lang="scss" scoped></style> |
0 commit comments