mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 10:12:51 +00:00
feat: 右侧点击展示菜单 (#1171)
This commit is contained in:
parent
2ea9e02b66
commit
1bc9f9f2b9
|
|
@ -4,23 +4,28 @@
|
|||
"id": "base-node",
|
||||
"type": "base-node",
|
||||
"x": 440,
|
||||
"y": 3350,
|
||||
"y": 3040,
|
||||
"properties": {
|
||||
"config": {},
|
||||
"height": 517,
|
||||
"config": {
|
||||
|
||||
},
|
||||
"height": 825.6,
|
||||
"stepName": "基本信息",
|
||||
"node_data": {
|
||||
"desc": "",
|
||||
"name": "",
|
||||
"name": "maxkbapplication",
|
||||
"prologue": "您好,我是 MaxKB 小助手,您可以向我提出 MaxKB 使用问题。\n- MaxKB 主要功能有什么?\n- MaxKB 支持哪些大语言模型?\n- MaxKB 支持哪些文档类型?"
|
||||
}
|
||||
},
|
||||
"input_field_list": [
|
||||
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "start-node",
|
||||
"type": "start-node",
|
||||
"x": 440,
|
||||
"y": 3710,
|
||||
"x": 430,
|
||||
"y": 3660,
|
||||
"properties": {
|
||||
"config": {
|
||||
"fields": [
|
||||
|
|
@ -31,8 +36,8 @@
|
|||
],
|
||||
"globalFields": [
|
||||
{
|
||||
"value": "time",
|
||||
"label": "当前时间"
|
||||
"label": "当前时间",
|
||||
"value": "time"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -42,7 +47,7 @@
|
|||
"value": "question"
|
||||
}
|
||||
],
|
||||
"height": 268.533,
|
||||
"height": 276,
|
||||
"stepName": "开始",
|
||||
"globalFields": [
|
||||
{
|
||||
|
|
@ -55,8 +60,8 @@
|
|||
{
|
||||
"id": "b931efe5-5b66-46e0-ae3b-0160cb18eeb5",
|
||||
"type": "search-dataset-node",
|
||||
"x": 830,
|
||||
"y": 3470,
|
||||
"x": 840,
|
||||
"y": 3210,
|
||||
"properties": {
|
||||
"config": {
|
||||
"fields": [
|
||||
|
|
@ -78,10 +83,12 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"height": 754.8,
|
||||
"height": 794,
|
||||
"stepName": "知识库检索",
|
||||
"node_data": {
|
||||
"dataset_id_list": [],
|
||||
"dataset_id_list": [
|
||||
|
||||
],
|
||||
"dataset_setting": {
|
||||
"top_n": 3,
|
||||
"similarity": 0.6,
|
||||
|
|
@ -91,6 +98,9 @@
|
|||
"question_reference_address": [
|
||||
"start-node",
|
||||
"question"
|
||||
],
|
||||
"source_dataset_id_list": [
|
||||
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -98,8 +108,8 @@
|
|||
{
|
||||
"id": "fc60863a-dec2-4854-9e5a-7a44b7187a2b",
|
||||
"type": "condition-node",
|
||||
"x": 1380,
|
||||
"y": 3470,
|
||||
"x": 1490,
|
||||
"y": 3210,
|
||||
"properties": {
|
||||
"width": 600,
|
||||
"config": {
|
||||
|
|
@ -110,7 +120,7 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"height": 524.6669999999999,
|
||||
"height": 543.675,
|
||||
"stepName": "判断器",
|
||||
"node_data": {
|
||||
"branch": [
|
||||
|
|
@ -148,24 +158,26 @@
|
|||
"id": "161",
|
||||
"type": "ELSE",
|
||||
"condition": "and",
|
||||
"conditions": []
|
||||
"conditions": [
|
||||
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"branch_condition_list": [
|
||||
{
|
||||
"index": 0,
|
||||
"height": 116.133,
|
||||
"height": 121.225,
|
||||
"id": "1009"
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"height": 116.133,
|
||||
"height": 121.225,
|
||||
"id": "4908"
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"height": 40,
|
||||
"height": 44,
|
||||
"id": "161"
|
||||
}
|
||||
]
|
||||
|
|
@ -174,8 +186,8 @@
|
|||
{
|
||||
"id": "4ffe1086-25df-4c85-b168-979b5bbf0a26",
|
||||
"type": "reply-node",
|
||||
"x": 2090,
|
||||
"y": 2820,
|
||||
"x": 2170,
|
||||
"y": 2480,
|
||||
"properties": {
|
||||
"config": {
|
||||
"fields": [
|
||||
|
|
@ -185,7 +197,7 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"height": 312.267,
|
||||
"height": 378,
|
||||
"stepName": "指定回复",
|
||||
"node_data": {
|
||||
"fields": [
|
||||
|
|
@ -193,15 +205,16 @@
|
|||
"directly_return"
|
||||
],
|
||||
"content": "",
|
||||
"reply_type": "referencing"
|
||||
"reply_type": "referencing",
|
||||
"is_result": true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "f1f1ee18-5a02-46f6-b4e6-226253cdffbb",
|
||||
"type": "ai-chat-node",
|
||||
"x": 2090,
|
||||
"y": 3460,
|
||||
"x": 2160,
|
||||
"y": 3200,
|
||||
"properties": {
|
||||
"config": {
|
||||
"fields": [
|
||||
|
|
@ -211,21 +224,22 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"height": 681.4,
|
||||
"height": 763,
|
||||
"stepName": "AI 对话",
|
||||
"node_data": {
|
||||
"prompt": "已知信息:\n{{知识库检索.data}}\n问题:\n{{开始.question}}",
|
||||
"system": "",
|
||||
"model_id": "",
|
||||
"dialogue_number": 0
|
||||
"dialogue_number": 0,
|
||||
"is_result": true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "309d0eef-c597-46b5-8d51-b9a28aaef4c7",
|
||||
"type": "ai-chat-node",
|
||||
"x": 2090,
|
||||
"y": 4180,
|
||||
"x": 2160,
|
||||
"y": 3970,
|
||||
"properties": {
|
||||
"config": {
|
||||
"fields": [
|
||||
|
|
@ -235,13 +249,14 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"height": 681.4,
|
||||
"height": 763,
|
||||
"stepName": "AI 对话1",
|
||||
"node_data": {
|
||||
"prompt": "{{开始.question}}",
|
||||
"system": "",
|
||||
"model_id": "",
|
||||
"dialogue_number": 0
|
||||
"dialogue_number": 0,
|
||||
"is_result": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -253,30 +268,32 @@
|
|||
"sourceNodeId": "start-node",
|
||||
"targetNodeId": "b931efe5-5b66-46e0-ae3b-0160cb18eeb5",
|
||||
"startPoint": {
|
||||
"x": 600,
|
||||
"y": 3710
|
||||
"x": 590,
|
||||
"y": 3660
|
||||
},
|
||||
"endPoint": {
|
||||
"x": 670,
|
||||
"y": 3470
|
||||
"x": 680,
|
||||
"y": 3210
|
||||
},
|
||||
"properties": {
|
||||
|
||||
},
|
||||
"properties": {},
|
||||
"pointsList": [
|
||||
{
|
||||
"x": 600,
|
||||
"y": 3710
|
||||
"x": 590,
|
||||
"y": 3660
|
||||
},
|
||||
{
|
||||
"x": 710,
|
||||
"y": 3710
|
||||
"x": 700,
|
||||
"y": 3660
|
||||
},
|
||||
{
|
||||
"x": 560,
|
||||
"y": 3470
|
||||
"x": 570,
|
||||
"y": 3210
|
||||
},
|
||||
{
|
||||
"x": 670,
|
||||
"y": 3470
|
||||
"x": 680,
|
||||
"y": 3210
|
||||
}
|
||||
],
|
||||
"sourceAnchorId": "start-node_right",
|
||||
|
|
@ -288,30 +305,32 @@
|
|||
"sourceNodeId": "b931efe5-5b66-46e0-ae3b-0160cb18eeb5",
|
||||
"targetNodeId": "fc60863a-dec2-4854-9e5a-7a44b7187a2b",
|
||||
"startPoint": {
|
||||
"x": 990,
|
||||
"y": 3470
|
||||
"x": 1000,
|
||||
"y": 3210
|
||||
},
|
||||
"endPoint": {
|
||||
"x": 1090,
|
||||
"y": 3470
|
||||
"x": 1200,
|
||||
"y": 3210
|
||||
},
|
||||
"properties": {
|
||||
|
||||
},
|
||||
"properties": {},
|
||||
"pointsList": [
|
||||
{
|
||||
"x": 990,
|
||||
"y": 3470
|
||||
"x": 1000,
|
||||
"y": 3210
|
||||
},
|
||||
{
|
||||
"x": 1100,
|
||||
"y": 3470
|
||||
},
|
||||
{
|
||||
"x": 980,
|
||||
"y": 3470
|
||||
"x": 1110,
|
||||
"y": 3210
|
||||
},
|
||||
{
|
||||
"x": 1090,
|
||||
"y": 3470
|
||||
"y": 3210
|
||||
},
|
||||
{
|
||||
"x": 1200,
|
||||
"y": 3210
|
||||
}
|
||||
],
|
||||
"sourceAnchorId": "b931efe5-5b66-46e0-ae3b-0160cb18eeb5_right",
|
||||
|
|
@ -323,30 +342,32 @@
|
|||
"sourceNodeId": "fc60863a-dec2-4854-9e5a-7a44b7187a2b",
|
||||
"targetNodeId": "4ffe1086-25df-4c85-b168-979b5bbf0a26",
|
||||
"startPoint": {
|
||||
"x": 1670,
|
||||
"y": 3340.733
|
||||
"x": 1780,
|
||||
"y": 3073.775
|
||||
},
|
||||
"endPoint": {
|
||||
"x": 1930,
|
||||
"y": 2820
|
||||
"x": 2010,
|
||||
"y": 2480
|
||||
},
|
||||
"properties": {
|
||||
|
||||
},
|
||||
"properties": {},
|
||||
"pointsList": [
|
||||
{
|
||||
"x": 1670,
|
||||
"y": 3340.733
|
||||
},
|
||||
{
|
||||
"x": 1780,
|
||||
"y": 3340.733
|
||||
"y": 3073.775
|
||||
},
|
||||
{
|
||||
"x": 1820,
|
||||
"y": 2820
|
||||
"x": 1890,
|
||||
"y": 3073.775
|
||||
},
|
||||
{
|
||||
"x": 1930,
|
||||
"y": 2820
|
||||
"x": 1900,
|
||||
"y": 2480
|
||||
},
|
||||
{
|
||||
"x": 2010,
|
||||
"y": 2480
|
||||
}
|
||||
],
|
||||
"sourceAnchorId": "fc60863a-dec2-4854-9e5a-7a44b7187a2b_1009_right",
|
||||
|
|
@ -358,30 +379,32 @@
|
|||
"sourceNodeId": "fc60863a-dec2-4854-9e5a-7a44b7187a2b",
|
||||
"targetNodeId": "f1f1ee18-5a02-46f6-b4e6-226253cdffbb",
|
||||
"startPoint": {
|
||||
"x": 1670,
|
||||
"y": 3464.866
|
||||
"x": 1780,
|
||||
"y": 3203
|
||||
},
|
||||
"endPoint": {
|
||||
"x": 1930,
|
||||
"y": 3460
|
||||
"x": 2000,
|
||||
"y": 3200
|
||||
},
|
||||
"properties": {
|
||||
|
||||
},
|
||||
"properties": {},
|
||||
"pointsList": [
|
||||
{
|
||||
"x": 1670,
|
||||
"y": 3464.866
|
||||
},
|
||||
{
|
||||
"x": 1780,
|
||||
"y": 3464.866
|
||||
"y": 3203
|
||||
},
|
||||
{
|
||||
"x": 1820,
|
||||
"y": 3460
|
||||
"x": 1890,
|
||||
"y": 3203
|
||||
},
|
||||
{
|
||||
"x": 1930,
|
||||
"y": 3460
|
||||
"x": 1890,
|
||||
"y": 3200
|
||||
},
|
||||
{
|
||||
"x": 2000,
|
||||
"y": 3200
|
||||
}
|
||||
],
|
||||
"sourceAnchorId": "fc60863a-dec2-4854-9e5a-7a44b7187a2b_4908_right",
|
||||
|
|
@ -393,30 +416,32 @@
|
|||
"sourceNodeId": "fc60863a-dec2-4854-9e5a-7a44b7187a2b",
|
||||
"targetNodeId": "309d0eef-c597-46b5-8d51-b9a28aaef4c7",
|
||||
"startPoint": {
|
||||
"x": 1670,
|
||||
"y": 3550.9325000000003
|
||||
"x": 1780,
|
||||
"y": 3293.6124999999997
|
||||
},
|
||||
"endPoint": {
|
||||
"x": 1930,
|
||||
"y": 4180
|
||||
"x": 2000,
|
||||
"y": 3970
|
||||
},
|
||||
"properties": {
|
||||
|
||||
},
|
||||
"properties": {},
|
||||
"pointsList": [
|
||||
{
|
||||
"x": 1670,
|
||||
"y": 3550.9325000000003
|
||||
},
|
||||
{
|
||||
"x": 1780,
|
||||
"y": 3550.9325000000003
|
||||
"y": 3293.6124999999997
|
||||
},
|
||||
{
|
||||
"x": 1820,
|
||||
"y": 4180
|
||||
"x": 1890,
|
||||
"y": 3293.6124999999997
|
||||
},
|
||||
{
|
||||
"x": 1930,
|
||||
"y": 4180
|
||||
"x": 1890,
|
||||
"y": 3970
|
||||
},
|
||||
{
|
||||
"x": 2000,
|
||||
"y": 3970
|
||||
}
|
||||
],
|
||||
"sourceAnchorId": "fc60863a-dec2-4854-9e5a-7a44b7187a2b_161_right",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,149 @@
|
|||
<template>
|
||||
<div v-show="show" class="workflow-dropdown-menu border border-r-4">
|
||||
<el-tabs v-model="activeName" class="workflow-dropdown-tabs">
|
||||
<el-tab-pane label="基础组件" name="base">
|
||||
<template v-for="(item, index) in menuNodes" :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>
|
||||
</div>
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="函数库" name="function">
|
||||
<el-scrollbar max-height="300">
|
||||
<div
|
||||
class="workflow-dropdown-item cursor flex p-8-12"
|
||||
@click.stop="clickNodes(functionNode)"
|
||||
@mousedown.stop="onmousedown(functionNode)"
|
||||
>
|
||||
<component :is="iconComponent(`function-lib-node-icon`)" class="mr-8 mt-4" :size="32" />
|
||||
<div class="pre-wrap">
|
||||
<div class="lighter">{{ functionNode.label }}</div>
|
||||
<el-text type="info" size="small">{{ functionNode.text }}</el-text>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template v-for="(item, index) in functionLibList" :key="index">
|
||||
<div
|
||||
class="workflow-dropdown-item cursor flex p-8-12"
|
||||
@click.stop="clickNodes(functionLibNode, item)"
|
||||
@mousedown.stop="onmousedown(functionLibNode, item)"
|
||||
>
|
||||
<component
|
||||
:is="iconComponent(`function-lib-node-icon`)"
|
||||
class="mr-8 mt-4"
|
||||
:size="32"
|
||||
/>
|
||||
<div class="pre-wrap">
|
||||
<div class="lighter">{{ item.name }}</div>
|
||||
<el-text type="info" size="small">{{ item.desc }}</el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-scrollbar>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, watch, onMounted } from 'vue'
|
||||
import { menuNodes, functionLibNode, functionNode } from '@/workflow/common/data'
|
||||
import { iconComponent } from '@/workflow/icons/utils'
|
||||
import applicationApi from '@/api/application'
|
||||
|
||||
const props = defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
id: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
workflowRef: Object
|
||||
})
|
||||
|
||||
const emit = defineEmits(['clickNodes', 'onmousedown'])
|
||||
|
||||
const loading = ref(false)
|
||||
const activeName = ref('base')
|
||||
|
||||
const functionLibList = ref<any[]>([])
|
||||
|
||||
function clickNodes(item: any, data?: any) {
|
||||
if (data) {
|
||||
item['properties']['stepName'] = data.name
|
||||
item['properties']['node_data'] = {
|
||||
...data,
|
||||
function_lib_id: data.id,
|
||||
input_field_list: data.input_field_list.map((field: any) => ({
|
||||
...field,
|
||||
value: field.source == 'reference' ? [] : ''
|
||||
}))
|
||||
}
|
||||
}
|
||||
props.workflowRef?.addNode(item)
|
||||
|
||||
emit('clickNodes', item)
|
||||
}
|
||||
|
||||
function onmousedown(item: any, data?: any) {
|
||||
if (data) {
|
||||
item['properties']['stepName'] = data.name
|
||||
item['properties']['node_data'] = {
|
||||
...data,
|
||||
function_lib_id: data.id,
|
||||
input_field_list: data.input_field_list.map((field: any) => ({
|
||||
...field,
|
||||
value: field.source == 'reference' ? [] : ''
|
||||
}))
|
||||
}
|
||||
}
|
||||
props.workflowRef?.onmousedown(item)
|
||||
emit('onmousedown', item)
|
||||
}
|
||||
|
||||
function getList() {
|
||||
applicationApi.listFunctionLib(props.id, loading).then((res: any) => {
|
||||
functionLibList.value = res.data
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.workflow-dropdown-menu {
|
||||
-moz-user-select: none; /* Firefox */
|
||||
-webkit-user-select: none; /* WebKit内核 */
|
||||
-ms-user-select: none; /* IE10及以后 */
|
||||
-khtml-user-select: none; /* 早期浏览器 */
|
||||
-o-user-select: none; /* Opera */
|
||||
user-select: none; /* CSS3属性 */
|
||||
position: absolute;
|
||||
top: 49px;
|
||||
right: 90px;
|
||||
z-index: 99;
|
||||
width: 268px;
|
||||
box-shadow: 0px 4px 8px 0px var(--app-text-color-light-1);
|
||||
background: #ffffff;
|
||||
padding-bottom: 8px;
|
||||
|
||||
.title {
|
||||
padding: 12px 12px 4px;
|
||||
}
|
||||
.workflow-dropdown-item {
|
||||
&:hover {
|
||||
background: var(--app-text-color-light-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -25,66 +25,14 @@
|
|||
</div>
|
||||
<!-- 下拉框 -->
|
||||
<el-collapse-transition>
|
||||
<div
|
||||
v-show="showPopover"
|
||||
class="workflow-dropdown-menu border border-r-4"
|
||||
<DropdownMenu
|
||||
:show="showPopover"
|
||||
:id="id"
|
||||
v-click-outside="clickoutside"
|
||||
>
|
||||
<el-tabs v-model="activeName" class="workflow-dropdown-tabs">
|
||||
<el-tab-pane label="基础组件" name="base">
|
||||
<template v-for="(item, index) in menuNodes" :key="index">
|
||||
<div
|
||||
class="workflow-dropdown-item cursor flex p-8-12"
|
||||
@click="clickNodes(item)"
|
||||
@mousedown="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>
|
||||
</div>
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="函数库" name="function">
|
||||
<el-scrollbar max-height="300">
|
||||
<div
|
||||
class="workflow-dropdown-item cursor flex p-8-12"
|
||||
@click="clickNodes(functionNode)"
|
||||
@mousedown="onmousedown(functionNode)"
|
||||
>
|
||||
<component
|
||||
:is="iconComponent(`function-lib-node-icon`)"
|
||||
class="mr-8 mt-4"
|
||||
:size="32"
|
||||
/>
|
||||
<div class="pre-wrap">
|
||||
<div class="lighter">{{ functionNode.label }}</div>
|
||||
<el-text type="info" size="small">{{ functionNode.text }}</el-text>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template v-for="(item, index) in functionLibList" :key="index">
|
||||
<div
|
||||
class="workflow-dropdown-item cursor flex p-8-12"
|
||||
@click="clickNodes(functionLibNode, item)"
|
||||
@mousedown="onmousedown(functionLibNode, item)"
|
||||
>
|
||||
<component
|
||||
:is="iconComponent(`function-lib-node-icon`)"
|
||||
class="mr-8 mt-4"
|
||||
:size="32"
|
||||
/>
|
||||
<div class="pre-wrap">
|
||||
<div class="lighter">{{ item.name }}</div>
|
||||
<el-text type="info" size="small">{{ item.desc }}</el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-scrollbar>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
@clickNodes="clickNodes"
|
||||
@onmousedown="onmousedown"
|
||||
:workflowRef="workflowRef"
|
||||
/>
|
||||
</el-collapse-transition>
|
||||
<!-- 主画布 -->
|
||||
<div class="workflow-main">
|
||||
|
|
@ -148,8 +96,7 @@
|
|||
import { ref, onMounted, onBeforeUnmount, computed } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import Workflow from '@/workflow/index.vue'
|
||||
import { menuNodes, functionLibNode, functionNode } from '@/workflow/common/data'
|
||||
import { iconComponent } from '@/workflow/icons/utils'
|
||||
import DropdownMenu from '@/views/application-workflow/component/DropdownMenu.vue'
|
||||
import applicationApi from '@/api/application'
|
||||
import { isAppIcon } from '@/utils/application'
|
||||
import { MsgSuccess, MsgConfirm, MsgError } from '@/utils/message'
|
||||
|
|
@ -179,9 +126,19 @@ const showPopover = ref(false)
|
|||
const showDebug = ref(false)
|
||||
const enlarge = ref(false)
|
||||
const saveTime = ref<any>('')
|
||||
const activeName = ref('base')
|
||||
const functionLibList = ref<any[]>([])
|
||||
|
||||
function clickNodes(item: any) {
|
||||
// workflowRef.value?.addNode(item)
|
||||
showPopover.value = false
|
||||
}
|
||||
|
||||
function onmousedown(item: any) {
|
||||
// workflowRef.value?.onmousedown(item)
|
||||
showPopover.value = false
|
||||
}
|
||||
function clickoutside() {
|
||||
showPopover.value = false
|
||||
}
|
||||
function publicHandle() {
|
||||
workflowRef.value
|
||||
?.validate()
|
||||
|
|
@ -206,9 +163,6 @@ function publicHandle() {
|
|||
})
|
||||
}
|
||||
|
||||
function clickoutside() {
|
||||
showPopover.value = false
|
||||
}
|
||||
const clickShowDebug = () => {
|
||||
workflowRef.value
|
||||
?.validate()
|
||||
|
|
@ -247,38 +201,6 @@ function clickoutsideDebug(e: any) {
|
|||
}
|
||||
}
|
||||
|
||||
function clickNodes(item: any, data?: any) {
|
||||
if (data) {
|
||||
item['properties']['stepName'] = data.name
|
||||
item['properties']['node_data'] = {
|
||||
...data,
|
||||
function_lib_id: data.id,
|
||||
input_field_list: data.input_field_list.map((field: any) => ({
|
||||
...field,
|
||||
value: field.source == 'reference' ? [] : ''
|
||||
}))
|
||||
}
|
||||
}
|
||||
workflowRef.value?.addNode(item)
|
||||
showPopover.value = false
|
||||
}
|
||||
|
||||
function onmousedown(item: any, data?: any) {
|
||||
if (data) {
|
||||
item['properties']['stepName'] = data.name
|
||||
item['properties']['node_data'] = {
|
||||
...data,
|
||||
function_lib_id: data.id,
|
||||
input_field_list: data.input_field_list.map((field: any) => ({
|
||||
...field,
|
||||
value: field.source == 'reference' ? [] : ''
|
||||
}))
|
||||
}
|
||||
}
|
||||
workflowRef.value?.onmousedown(item)
|
||||
showPopover.value = false
|
||||
}
|
||||
|
||||
function getGraphData() {
|
||||
return workflowRef.value?.getGraphData()
|
||||
}
|
||||
|
|
@ -308,12 +230,6 @@ function saveApplication(bool?: boolean) {
|
|||
})
|
||||
}
|
||||
|
||||
function getList() {
|
||||
applicationApi.listFunctionLib(id, loading).then((res: any) => {
|
||||
functionLibList.value = res.data
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时保存
|
||||
*/
|
||||
|
|
@ -334,7 +250,7 @@ const closeInterval = () => {
|
|||
|
||||
onMounted(() => {
|
||||
getDetail()
|
||||
getList()
|
||||
|
||||
// 初始化定时任务
|
||||
if (hasPermission(`APPLICATION:MANAGE:${id}`, 'AND')) {
|
||||
initInterval()
|
||||
|
|
@ -358,31 +274,7 @@ onBeforeUnmount(() => {
|
|||
height: calc(100vh - 62px);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.workflow-dropdown-menu {
|
||||
-moz-user-select: none; /* Firefox */
|
||||
-webkit-user-select: none; /* WebKit内核 */
|
||||
-ms-user-select: none; /* IE10及以后 */
|
||||
-khtml-user-select: none; /* 早期浏览器 */
|
||||
-o-user-select: none; /* Opera */
|
||||
user-select: none; /* CSS3属性 */
|
||||
position: absolute;
|
||||
top: 49px;
|
||||
right: 90px;
|
||||
z-index: 99;
|
||||
width: 268px;
|
||||
box-shadow: 0px 4px 8px 0px var(--app-text-color-light-1);
|
||||
background: #ffffff;
|
||||
padding-bottom: 8px;
|
||||
|
||||
.title {
|
||||
padding: 12px 12px 4px;
|
||||
}
|
||||
.workflow-dropdown-item {
|
||||
&:hover {
|
||||
background: var(--app-text-color-light-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
.workflow-dropdown-tabs {
|
||||
.el-tabs__nav-wrap {
|
||||
padding: 0 16px;
|
||||
|
|
|
|||
|
|
@ -82,15 +82,35 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-collapse-transition>
|
||||
<DropdownMenu
|
||||
v-if="showAnchor"
|
||||
@mousemove.stop
|
||||
@mousedown.stop
|
||||
@keydown.stop
|
||||
@click.stop
|
||||
:show="showAnchor"
|
||||
:id="id"
|
||||
style="left: 100%; top: 50%; transform: translate(0, -50%)"
|
||||
@clickNodes="clickNodes"
|
||||
/>
|
||||
</el-collapse-transition>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { app } from '@/main'
|
||||
import DropdownMenu from '@/views/application-workflow/component/DropdownMenu.vue'
|
||||
import { set } from 'lodash'
|
||||
import { iconComponent } from '../icons/utils'
|
||||
import { copyClick } from '@/utils/clipboard'
|
||||
import { WorkflowType } from '@/enums/workflow'
|
||||
import { MsgError, MsgConfirm } from '@/utils/message'
|
||||
|
||||
const {
|
||||
params: { id }
|
||||
} = app.config.globalProperties.$route as any
|
||||
|
||||
const height = ref<{
|
||||
stepContainerHeight: number
|
||||
inputContainerHeight: number
|
||||
|
|
@ -100,7 +120,8 @@ const height = ref<{
|
|||
inputContainerHeight: 0,
|
||||
outputContainerHeight: 0
|
||||
})
|
||||
|
||||
const showAnchor = ref<boolean>(false)
|
||||
const anchorData = ref<any>()
|
||||
const node_status = computed(() => {
|
||||
if (props.nodeModel.properties.status) {
|
||||
return props.nodeModel.properties.status
|
||||
|
|
@ -152,6 +173,23 @@ const resizeStepContainer = (wh: any) => {
|
|||
}
|
||||
}
|
||||
|
||||
function clickNodes(item: any) {
|
||||
const nodeModel = props.nodeModel.graphModel.addNode({
|
||||
type: item.type,
|
||||
properties: item.properties,
|
||||
x: anchorData.value?.x + props.nodeModel.width + 100,
|
||||
y: anchorData.value?.y - item.height
|
||||
})
|
||||
props.nodeModel.graphModel.addEdge({
|
||||
type: 'app-edge',
|
||||
sourceNodeId: props.nodeModel.id,
|
||||
sourceAnchorId: anchorData.value?.id,
|
||||
targetNodeId: nodeModel.id
|
||||
})
|
||||
|
||||
closeNodeMenu()
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
nodeModel: any
|
||||
}>()
|
||||
|
|
@ -173,6 +211,19 @@ const nodeFields = computed(() => {
|
|||
function showOperate(type: string) {
|
||||
return type !== WorkflowType.Base && type !== WorkflowType.Start
|
||||
}
|
||||
const openNodeMenu = (anchorValue: any) => {
|
||||
showAnchor.value = true
|
||||
anchorData.value = anchorValue
|
||||
}
|
||||
const closeNodeMenu = () => {
|
||||
showAnchor.value = false
|
||||
anchorData.value = undefined
|
||||
}
|
||||
onMounted(() => {
|
||||
set(props.nodeModel, 'openNodeMenu', (anchorData: any) => {
|
||||
showAnchor.value ? closeNodeMenu() : openNodeMenu(anchorData)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.workflow-node-container {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ class AppNode extends HtmlResize.view {
|
|||
constructor(props: any, VueNode: any) {
|
||||
super(props)
|
||||
this.isMounted = false
|
||||
|
||||
this.r = h(VueNode, {
|
||||
properties: props.model.properties,
|
||||
nodeModel: props.model
|
||||
|
|
@ -70,6 +69,12 @@ class AppNode extends HtmlResize.view {
|
|||
},
|
||||
[
|
||||
lh('div', {
|
||||
style: { zindex: 0 },
|
||||
onClick: () => {
|
||||
if (!isConnect && type == 'right') {
|
||||
this.props.model.openNodeMenu(anchorData)
|
||||
}
|
||||
},
|
||||
dangerouslySetInnerHTML: {
|
||||
__html: isConnect
|
||||
? `<svg width="100%" height="100%" viewBox="0 0 42 42" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
|
|
|
|||
|
|
@ -29,9 +29,11 @@ export const baseNode = {
|
|||
type: WorkflowType.Base,
|
||||
x: 200,
|
||||
y: 270,
|
||||
text: '',
|
||||
properties: {
|
||||
height: 200,
|
||||
stepName: '基本信息',
|
||||
input_field_list: [],
|
||||
node_data: {
|
||||
name: '',
|
||||
desc: '',
|
||||
|
|
@ -53,6 +55,7 @@ export const aiChatNode = {
|
|||
type: WorkflowType.AiChat,
|
||||
text: '与 AI 大模型进行对话',
|
||||
label: 'AI 对话',
|
||||
height: 340,
|
||||
properties: {
|
||||
stepName: 'AI 对话',
|
||||
config: {
|
||||
|
|
@ -72,6 +75,7 @@ export const searchDatasetNode = {
|
|||
type: WorkflowType.SearchDataset,
|
||||
text: '关联知识库,查找与问题相关的分段',
|
||||
label: '知识库检索',
|
||||
height: 355,
|
||||
properties: {
|
||||
stepName: '知识库检索',
|
||||
config: {
|
||||
|
|
@ -94,6 +98,7 @@ export const questionNode = {
|
|||
type: WorkflowType.Question,
|
||||
text: '根据历史聊天记录优化完善当前问题,更利于匹配知识库分段',
|
||||
label: '问题优化',
|
||||
height: 345,
|
||||
properties: {
|
||||
stepName: '问题优化',
|
||||
config: {
|
||||
|
|
@ -110,6 +115,7 @@ export const conditionNode = {
|
|||
type: WorkflowType.Condition,
|
||||
text: '根据不同条件执行不同的节点',
|
||||
label: '判断器',
|
||||
height: 175,
|
||||
properties: {
|
||||
width: 600,
|
||||
stepName: '判断器',
|
||||
|
|
@ -127,6 +133,7 @@ export const replyNode = {
|
|||
type: WorkflowType.Reply,
|
||||
text: '指定回复内容,引用变量会转换为字符串进行输出',
|
||||
label: '指定回复',
|
||||
height: 210,
|
||||
properties: {
|
||||
stepName: '指定回复',
|
||||
config: {
|
||||
|
|
@ -143,6 +150,7 @@ export const rerankerNode = {
|
|||
type: WorkflowType.RrerankerNode,
|
||||
text: '使用重排模型对多个知识库的检索结果进行二次召回',
|
||||
label: '多路召回',
|
||||
height: 252,
|
||||
properties: {
|
||||
stepName: '多路召回',
|
||||
config: {
|
||||
|
|
@ -171,6 +179,7 @@ export const functionNode = {
|
|||
type: WorkflowType.FunctionLibCustom,
|
||||
text: '通过执行自定义脚本,实现数据处理',
|
||||
label: '自定义函数',
|
||||
height: 260,
|
||||
properties: {
|
||||
stepName: '自定义函数',
|
||||
config: {
|
||||
|
|
@ -187,6 +196,7 @@ export const functionLibNode = {
|
|||
type: WorkflowType.FunctionLib,
|
||||
text: '通过执行自定义脚本,实现数据处理',
|
||||
label: '自定义函数',
|
||||
height: 170,
|
||||
properties: {
|
||||
stepName: '自定义函数',
|
||||
config: {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import BaseNodeVue from './index.vue'
|
||||
import { AppNode, AppNodeModel } from '@/workflow/common/app-node'
|
||||
|
||||
class BaseNode extends AppNode {
|
||||
constructor(props: any) {
|
||||
super(props, BaseNodeVue)
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@
|
|||
<el-switch size="small" v-model="form_data.stt_model_enable" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-select
|
||||
v-model="form_data.stt_model_id"
|
||||
class="w-full"
|
||||
|
|
@ -182,8 +183,8 @@
|
|||
</div>
|
||||
</template>
|
||||
<el-radio-group v-model="form_data.tts_type">
|
||||
<el-radio value="BROWSER">浏览器播放(免费)</el-radio>
|
||||
<el-radio value="TTS">TTS模型</el-radio>
|
||||
<el-radio label="浏览器播放(免费)" value="BROWSER" />
|
||||
<el-radio label="TTS模型" value="TTS" />
|
||||
</el-radio-group>
|
||||
<el-select
|
||||
v-if="form_data.tts_type === 'TTS'"
|
||||
|
|
@ -246,6 +247,53 @@
|
|||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<div class="flex-between">
|
||||
全局变量
|
||||
<el-button link type="primary" @click="openAddDialog()">
|
||||
<el-icon class="mr-4"><Plus /></el-icon> 添加
|
||||
</el-button>
|
||||
</div>
|
||||
<el-table :data="props.nodeModel.properties.input_field_list" class="mb-16">
|
||||
<el-table-column prop="name" label="变量名" />
|
||||
<el-table-column prop="variable" label="变量" />
|
||||
<el-table-column label="输入类型">
|
||||
<template #default="{ row }">
|
||||
<el-tag type="info" class="info-tag" v-if="row.type === 'input'">文本框</el-tag>
|
||||
<el-tag type="info" class="info-tag" v-if="row.type === 'date'">日期</el-tag>
|
||||
<el-tag type="info" class="info-tag" v-if="row.type === 'select'">下拉选项</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="必填">
|
||||
<template #default="{ row }">
|
||||
<div @click.stop>
|
||||
<el-switch size="small" v-model="row.is_required" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="source" label="赋值方式">
|
||||
<template #default="{ row }">
|
||||
{{ row.source === 'user_input' ? '用户输入' : '接口传参' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="left" width="80">
|
||||
<template #default="{ row, $index }">
|
||||
<span class="mr-4">
|
||||
<el-tooltip effect="dark" content="修改" placement="top">
|
||||
<el-button type="primary" text @click.stop="openAddDialog(row, $index)">
|
||||
<el-icon><EditPen /></el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
<el-tooltip effect="dark" content="删除" placement="top">
|
||||
<el-button type="primary" text @click="deleteField($index)">
|
||||
<el-icon>
|
||||
<Delete />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 回复内容弹出层 -->
|
||||
<el-dialog v-model="dialogVisible" title="开场白" append-to-body>
|
||||
<MdEditor v-model="cloneContent" :preview="false" :toolbars="[]" :footers="[]"></MdEditor>
|
||||
|
|
@ -255,8 +303,8 @@
|
|||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<FieldFormDialog ref="FieldFormDialogRef" @refresh="refreshFieldList" />
|
||||
</NodeContainer>
|
||||
<FieldFormDialog ref="FieldFormDialogRef" @refresh="refreshFieldList" />
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { app } from '@/main'
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ const envDir = './env'
|
|||
// https://vitejs.dev/config/
|
||||
export default defineConfig(({ mode }) => {
|
||||
const ENV = loadEnv(mode, envDir)
|
||||
const prefix = process.env.VITE_DYNAMIC_PREFIX || ENV.VITE_BASE_PATH;
|
||||
const proxyConf: Record<string, string | ProxyOptions> = {}
|
||||
proxyConf['/api'] = {
|
||||
target: 'http://127.0.0.1:8080',
|
||||
|
|
@ -18,7 +19,7 @@ export default defineConfig(({ mode }) => {
|
|||
return {
|
||||
preflight: false,
|
||||
lintOnSave: false,
|
||||
base: ENV.VITE_BASE_PATH,
|
||||
base: prefix,
|
||||
envDir: envDir,
|
||||
plugins: [vue(), DefineOptions()],
|
||||
server: {
|
||||
|
|
|
|||
Loading…
Reference in New Issue